发布时间:2023-04-22 文章分类:WEB开发, 电脑百科 投稿人:王小丽 字号: 默认 | | 超大 打印

前言:

在前端发出Ajax请求的时候,有时候会产生跨域问题,报错如下:

Access to XMLHttpRequest at 'http://127.0.0.1/api/post' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

针对以上问题,本文提供两种解决方案,CORS中间件和JSONP方法。

在具体介绍解决方法之前,我们先明确以下前提条件:

1、这两个方法都需要通过后端修改接口情况,无法单独通过前端解决跨域问题。

2、什么是跨域?什么情况会出现跨域?

答:当浏览器发起Ajax请求时,如果所请求的url和当前的url的协议、域名、端口存在任意不同,就会产生跨域问题。比如我在这个地址file:///C:/Users/%E8%8A%.html,协议为file协议,如果请求http协议的文件,自然就会出现跨域问题。

3、当我们使用script、img、herf加载内容时不会出现跨域问题

好,接来下我们先给出出现问题的前 后端代码,看看这个时候对应前后端都做了什么事:

首先是前端:使用ajax发送get请求,请求地址为http://127.0.0.1/api/get,由于前端页面使用file格式打开,所以在请求http协议的本机地址是会产生跨域问题。

$("#btnGET").on("click", function () {
          $.ajax({
            type: "GET",
            url: "http://127.0.0.1/api/get",
            success: function (res) {
              console.log(res);
            },
          });
        });

然后是后端:当请求的路由地址为/api/get的时候,返回对应的内容和query属性

app.get('/api/get',(req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query;
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: "GET 请求成功!", // 状态的描述
    data: query, // 需要响应给客户端的数据
  });
})

OK,说完发生跨域问题的情况,我们接下来讲解决方法:

方法一:引入cors中间件

这个方法很简单只要在后端加入两行代码。(首先要先npm install cors 安装包),修改后的后端代码如下

const cors = require("cors");
app.use(cors()); //使用cors中间件
app.get('/api/get',(req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query;
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: "GET 请求成功!", // 状态的描述
    data: query, // 需要响应给客户端的数据
  });
})

可以看到,引入了cors中间件之后,跨域问题可以得到解决,那么为什么解决,这么解决的原理是什么呢?让我们回到前面的报错内容:前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

 No 'Access-Control-Allow-Origin' header is present on the requested resource.意思就是说,所请求的资源没有Access-Control-Allow-Origin这个头,好的。那我们就把这个头给他安上,发现问题也可以解决,那么cors中间件是不是就是使用的这种方法呢?

app.get('/api/get',(req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  res.header("Access-Control-Allow-Origin", "*"); 设置响应头,*表示任何地址都亦可以访问
  const query = req.query;
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: "GET 请求成功!", // 状态的描述
    data: query, // 需要响应给客户端的数据
  });
})

我们发现当我们使用了cors中间件之后,使用浏览器抓包,可以看到相应头里确实有了这个字段

前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

 所以综上所述,cors中间件就是帮我们自动设置了响应头,从而解决跨域问题。

方法二:JSONP

简单来说,JSONP就是通过前端的script脚本从后端请求回来一段js代码并且执行从而获得数据,前端代码如下(视频截图下来的。。我懒得打字了)。。然后圈个重点JSONP只支持GET请求

来,我们解释一下:首先通过第一个script脚本注册一个函数f,那么这个函数自然就存在了,后面使用的脚本也能用f这个函数,这个道理和你用script引入一个jquery然后后面用 $ 开始一通操作是一样的道理。然后第二个script脚本访问一个跨域的资源,然后我们传入参数callback=f,这个参数有什么用呢?答:后端需要获取这个callback参数里面的值,然后把这个值(也就是f)拼接成一个函数然后返回回来给前端执行,对应后端代码如图。

前端代码:

前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

 后端代码:可以看到这个funcname对应的就是那个f,然后拼接一下就变成了f('你好'),那么这个东西就返回给了前端。但是但是前端这个时候注册了一个f函数呀,所以就会执行这个f('你好'),那么前端的数据也就请求回来了。前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

到这里,两种方法都讲完了,下面补充一种让我懵逼了很久的jquery的jsonp解决方法

直接上代码:(后端代码不变,还是拼接一个函数回来执行)

$("#btnJSONP").on("click", function () {
          $.ajax({
            type: "GET",
            url: "http://127.0.0.1/api/jsonp",
            dataType: "jsonp",
            jsonp: "callback",
            jsonpCallback: "f",
            success: function (res) {
              console.log(res);
            },
          });
        });

 打开控制台,可以看到jquery发送的这个请求其实和刚才是差不多的

前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

 同样是拼接了一个callback参数给后端,后端返回js代码,此外呢,上面这段代码的jsonp参数和jsonpcallback参数书可以省略的,那样的话jquery会自动给你贴一个值

前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

 前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

同时后端返回来的也就不再是那个f函数了。 

那么问题又来了,不是说ajax请求就会出现跨域问题,那为什么我这个用ajax发送jsonp请求就没有跨域呢?

答:我也不知道。然后就去查了一下jquery的文档。

 前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy

所以大概是因为没有用到XMLhttprequest这个对象,所以并不算一个真正的ajax请求把。

好了吃饭去了~