前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy
Posted 芒果mmmmg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy相关的知识,希望对你有一定的参考价值。
前言:
在前端发出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.
针对以上问题,本文提供两种解决方案,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中间件之后,跨域问题可以得到解决,那么为什么解决,这么解决的原理是什么呢?让我们回到前面的报错内容:
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中间件之后,使用浏览器抓包,可以看到相应头里确实有了这个字段
所以综上所述,cors中间件就是帮我们自动设置了响应头,从而解决跨域问题。
方法二:JSONP
简单来说,JSONP就是通过前端的script脚本从后端请求回来一段js代码并且执行从而获得数据,前端代码如下(视频截图下来的。。我懒得打字了)。。然后圈个重点JSONP只支持GET请求
来,我们解释一下:首先通过第一个script脚本注册一个函数f,那么这个函数自然就存在了,后面使用的脚本也能用f这个函数,这个道理和你用script引入一个jquery然后后面用 $ 开始一通操作是一样的道理。然后第二个script脚本访问一个跨域的资源,然后我们传入参数callback=f,这个参数有什么用呢?答:后端需要获取这个callback参数里面的值,然后把这个值(也就是f)拼接成一个函数然后返回回来给前端执行,对应后端代码如图。
前端代码:
后端代码:可以看到这个funcname对应的就是那个f,然后拼接一下就变成了f('你好'),那么这个东西就返回给了前端。但是但是前端这个时候注册了一个f函数呀,所以就会执行这个f('你好'),那么前端的数据也就请求回来了。
到这里,两种方法都讲完了,下面补充一种让我懵逼了很久的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发送的这个请求其实和刚才是差不多的
同样是拼接了一个callback参数给后端,后端返回js代码,此外呢,上面这段代码的jsonp参数和jsonpcallback参数书可以省略的,那样的话jquery会自动给你贴一个值
同时后端返回来的也就不再是那个f函数了。
那么问题又来了,不是说ajax请求就会出现跨域问题,那为什么我这个用ajax发送jsonp请求就没有跨域呢?
答:我也不知道。然后就去查了一下jquery的文档。
所以大概是因为没有用到XMLhttprequest这个对象,所以并不算一个真正的ajax请求把。
好了吃饭去了~
前端请求接口出现的跨域问题
1.针对跨域问题可以使用jsonp的方式解决
2.可以使用header头来定义
header(‘Access-Control-Allow-origin:*‘); header(‘Access-Control-Allow-Credentials:true‘); header(‘Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS‘); header(‘Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With‘); header(‘Content-Type: text/html; charset=utf-8‘);
加上以后就可以了
但是这个缺陷是IE10以下的不支持!一般手机应用都可以用!
以上是关于前端跨域问题的解决方案Access to XMLHttpRequest at ‘http..’ from origin ‘null‘ has been blocked by CORS policy的主要内容,如果未能解决你的问题,请参考以下文章
Access to Image at 'file:///Users canvas本地图片跨域报错解决方案
Access-Control-Allow-Origin跨域解决及详细介绍
遇到跨域问题:Access to XMLHttpRequest at ‘xxx‘ from origin ‘null‘ has been blocke,该怎么办?