如果你想学到更多实用前端知识。
可以关注我的公众号:【前端驿站Lite】,一个不止分享前端的地方 ᕦ( •̀∀•́)ᕤ
阅读完本篇文章,你将会有以下收获:
- 什么是同源策略
- 同源策略带来的限制
- 什么是 CORS 跨域资源共享
- 什么是 简单请求 和 非简单请求
- 什么是 OPTIONS 预检请求
- 服务端如何配置可以解决跨域问题
- 如何携带cookie进行跨域
什么是同源策略
同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口
相同。
出于安全考虑,浏览器只允许与同源的服务器进行交互,否则就会产生跨域
,浏览器控制台就会抛出异常。
同源策略带来的限制
有了同源策略后,我们日常开发中哪些行为会受到限制呢?
Cookie、LocalStorage、IndexDB
不同源无法共享,访问受限。DOM
video、audio、canvas、iframe 等DOM元素,不同源无法获取。XHR/Fetch 请求
不同源情况下,浏览器发起的请求会被拦截。
什么是 CORS
上面讲到不同源就会报错,那怎么与不同源的服务器进行交互呢?接下来 CORS
就要登场了。
CORS 是一个W3C标准 全称为 “跨域资源共享”(Cross-origin resource sharing),它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求。
两种请求方式
解决跨域问题之前,我们要先知道一个事情,浏览器发出请求分为 简单请求
和 非简单请求
那什么是简单请求呢?
满足以下两个条件的请求就是简单请求:
- 请求方法是以下三种方法之一:
HEAD
GET
POST
- HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
:只限于三个值application/x-www-form-urlencoded(表单提交)、multipart/form-data(文件上传)、text/plain(文本)
那什么是非简单请求呢?
简单请求之外的请求就是非简单请求,比如请求方法是 PUT
或者 DELETE
,或者 Content-Type
是 application/json
。
OPTIONS 预检请求
当我们非同源情况下,发出请求时,浏览器会先发出一个 OPTIONS
请求,这个请求叫做 预检请求
。用来检测服务器是否允许跨域请求。
只有预检请求通过后,才会发出真正的请求。
什么时候才会发送预检请求
是不是每次产生跨域都会发送预检请求呢?当然不是。
服务器响应头中设置 Access-Control-Max-Age
字段,表示预检请求的有效期,单位为秒。在有效期内,浏览器无需再次发出预检请求。
跨域请求头
当产生跨域时,浏览器会在请求头中添加 Origin
字段,表示请求来自哪个源。
服务端 CORS
前面说这么多,马上进入正题,如何配置服务端来解决跨域问题呢?
答案:服务端在response的header中配置以下字段:
Access-Control-Allow-Origin
字段,表示允许哪些源进行跨域请求。如果与请求头中的Origin
字段匹配,则允许跨域请求。
// 允许所有源进行跨域请求
res.header("Access-Control-Allow-Origin", "*");
// 或者 允许指定源进行跨域请求
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
Access-Control-Allow-Methods
字段,表示允许哪些请求方法进行跨域请求。
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
Access-Control-Allow-Headers
字段,表示带有哪些请求头的请求可以进行跨域请求。
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
跨域认证
到此,我们解决了跨域问题,但是还有一个问题,有些场景我们需要携带 Cookie
去请求,那这个问题如何解决呢?
第一步:前端请求中做如下配置:
- 如果使用fetch请求,需要设置
credentials
为include
fetch('http://localhost:3000', {
method: 'GET',
credentials: 'include'
})
- 如果使用xhr请求,需要设置
withCredentials
为true
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('GET', 'http://localhost:3000');
xhr.send();
第二步:服务端响应头中设置 Access-Control-Allow-Credentials
字段为 true
res.header("Access-Control-Allow-Credentials", "true");
这样我们就可以携带 Cookie
去请求了。
完结撒花,你又进步了一点点。
ᕦ( •̀∀•́)ᕤ