js网络请求---通过nodejs跨域请求数据

跨域请求       

        跨源资源共享CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。

        首先我们要知道为什么会有跨域问题,跨域是指,当前的网站访问了其他不同的(域、协议或端口)地址。大概意思就是被浏览器认定为不同源的两个地址不能互相访问,这保护了网页的隐私和安全。

        容易产生跨域的情况:网络请求其他页面的服务,a标签download下载陌生页的内容,canvas绘图使用未知的图片源......

浏览器认定为不同源可以参考

通过nodejs解决跨域

        既然在网页中跨域不好解决,那我们可以通过后端来访问(后端是没有同源策略的,这也是网络爬虫能爬取信息的原因),我们可以通过node的express服务拿到网络请求数据,在将数据传递给自己的网页(这里将express的响应设置为不限制同源访问)

        

let url = "https://api.tangdouz.com/a/biaoq.php";
// 这是一个表情包的api,直接访问会触发跨域
// 它有两个参数,一个是retrun 返回的数据格式,默认是text,可选json
// 一个是关键字 nr String 它会找出相关的表情包图片

直接在网页中对其发起get请求会产生跨域错误,所以我们通过nodejs拿数据

const express = require('express');

const app = express()
const port = 3000
let url = "https://api.tangdouz.com/a/biaoq.php";// 前端跨域的请求,通过后端请求解决跨域,在返回到前端
let params1 = "json";
let params2 = "笑脸"; // 默认没有参数时使用笑脸参数
let imgArr = [];// 用来存放图片信息

app.get('/img', (req, res) =>{
    // 在请求中设置响应头
    // 处理跨域问题
    res.header("Access-Control-Allow-Origin", "*"); // 设置响应头,*表示任何地址都亦可以访问
    console.log("收到一次访问,参数为:",req.query);
    if(req.query){
        params2 = req.query.str;
    }
    (async()=>{
        let response = await fetch(url+`?return=${params1}&nr=${params2}`,{"method":"get"});
        if(response.ok){// 访问成功对数据进行处理
            let data = await response.json();
            // console.log(data,response.status);
            for(let i = 0;i<data.length;i++){
                imgArr.push(data[i].thumbSrc);
            }
        }else{
            console.log("访问失败!",response.status)
        }
        console.log(imgArr);
        res.send(imgArr);// 将内容响应出去
        imgArr = [];// 响应后将数组置空
    })()
});

app.listen(port, () => console.log(`Example app listening on port http://127.0.0.1:${port}/img !`))
// 处理跨域问题
res.header("Access-Control-Allow-Origin", "*"); // 设置响应头,*表示任何地址都亦可以访问
// 解除同源限制

通过node启动服务

直接在网页中请求一次

可以看到能够拿到数据,

简单构建好node后,再写出前端页面,并以node提供的中间件进行数据访问

// index.js:

const search = document.getElementById("imgName");
const bt = document.getElementById("bt");
const imgList = document.getElementsByClassName("imgList")[0];
let url = "http://127.0.0.1:3000/img?str=";// node提供的api接口服务
let imgArr = [];
const re = new XMLHttpRequest();

bt.onclick = ()=>{
    // console.log(search.value);
    if(search.value){
        re.open("get",url+search.value);
        re.onload = ()=>{
            if(re.status == 200 && re.readyState == 4){
                // console.log(re.response);
                if(imgArr[0]){//页面上已有图片
                    // 对图片进行移除
                    let oldImgArr = document.getElementsByTagName("img");
                    while(oldImgArr.length>0){
                        // document.body.removeChild(oldImgArr[i]);
                        oldImgArr[0].remove();
                    }
                    // 重新渲染新图片
                    imgArr =JSON.parse(re.response);
                    for(let i =0 ;i<imgArr.length;i++){
                        let img = new Image();
                        img.src = imgArr[i];
                        imgList.appendChild(img);
                       
                    }
                }else{
                    imgArr =JSON.parse(re.response);
                    // 渲染新图片
                    for(let i =0 ;i<imgArr.length;i++){
                        let img = new Image();
                        img.src = imgArr[i];
                        imgList.appendChild(img);
                       
                    }
                }
            
            }else{
                console.log("请求失败");
            }
        }
        re.send();
    }else{
        alert("请输入正确的信息!");
    }
}
search.onkeydown = (e)=>{
    if(e.keyCode === 13){//回车键
        bt.onclick();
    }
    // console.log(e.keyCode);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表情包搜索</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="input-container">
        <input type="text" id="imgName" name="imgName" required="">
        <label for="input" class="label">表情包</label>
        <div class="underline"></div>   
        <button id = "bt" class="btn">
            <span class="icon"> 
                <svg width="19px" height="19px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path opacity="1" d="M14 5H20" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <path opacity="1" d="M14 8H17" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M21 11.5C21 16.75 16.75 21 11.5 21C6.25 21 2 16.75 2 11.5C2 6.25 6.25 2 11.5 2" stroke="" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"></path> <path opacity="1" d="M22 22L20 20" stroke="" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
            </span>
        </button>
    </div>
    <div class="imgList"></div>
    <script src="index.js"></script>
</body>
</html>

body {
    background-color: #e8f0fe;
}
.imgList{
    margin: auto;
    width: 90%;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-evenly;
    background-color: white;
}
.imgList img{
    object-fit: contain;/*保持原图的比例和大小*/
    flex-shrink: 0;
    margin-top: 10px;
    max-width: 95%;
}
.input-container {
    position: relative;
    margin: 50px auto;
    width: 500px;
    max-width: 90%;
}

.input-container input[type="text"] {
    font-size: 20px;
    width: 100%;
    border: none;
    border-bottom: 2px solid #ccc;
    padding: 5px 0;
    background-color: transparent;
    outline: none;
    color: #70d9ff;
}

.input-container .label {
    position: absolute;
    top: 0;
    left: 0;
    color: #ccc;
    transition: all 0.3s ease;
    pointer-events: none;
}

.input-container input[type="text"]:focus~.label,
.input-container input[type="text"]:valid~.label {
    top: -20px;
    font-size: 0.8em;
    color: #70d9ff;
}

.input-container .underline {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 2px;
    width: 100%;
    background-color: #333;
    transform: scaleX(0);
    transition: all 0.3s ease;
    background-color: #70d9ff;
}

.input-container input[type="text"]:focus~.underline,
.input-container input[type="text"]:valid~.underline {
    transform: scaleX(1);
}

.btn {
    position: absolute;
    left: calc(100% - 40px ) ;
    text-decoration: none;
    display: inline-block;
    width: 40px;
    height: 40px;
    transition: all 0.2s;
    border: none;
    border-radius: 50%;
    color: #ccc;
    background-color: transparent;
}

.btn:hover {
    transform: translateY(-3px);
    color: #70d9ff;
    /* box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); */
}
.icon svg{
    stroke: #ccc;
}
.btn:hover .icon svg{
    stroke: #70d9ff;
}

.btn:active {
    transform: translateY(-1px);
    /* box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); */
}

.btn::after {
    content: "";
    display: inline-block;
    height: 100%;
    width: 100%;
    border-radius: 100px;
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    transition: all .4s;
}

.btn::after {
    background-color: #e8f0fe;
}

.btn:hover::after {
    background-color: #ffffff;
    transform: scaleX(1.4) scaleY(1.6);
    opacity: 0;
}

 

最终会有4个文件:

express.js :提供中间服务拿数据

index.html :展示页

index.js :获取express拿到的数据

style.css :提供样式

查看结果:

注意:先启动node服务,再打开网页

可以看到我们的页面成功拿到了图片

思路总结

        这个方法的思路是:通过后端不受同源限制的原理拿数据,再将数据返回给自己的页面(因为是自己的后端服务,可以解开同源限制)

更多跨域解决方法可以参考

9种常见的前端跨域解决方案(详解) - 知乎 (zhihu.com)

  • 21
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值