最新总结 什么是同源策略,CORS 跨域资源共享解决前端跨域问题

如果你想学到更多实用前端知识。
可以关注我的公众号:【前端驿站Lite】,一个不止分享前端的地方 ᕦ( •̀∀•́)ᕤ

阅读完本篇文章,你将会有以下收获:

  1. 什么是同源策略
  2. 同源策略带来的限制
  3. 什么是 CORS 跨域资源共享
  4. 什么是 简单请求 和 非简单请求
  5. 什么是 OPTIONS 预检请求
  6. 服务端如何配置可以解决跨域问题
  7. 如何携带cookie进行跨域

什么是同源策略

同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口相同。

出于安全考虑,浏览器只允许与同源的服务器进行交互,否则就会产生跨域,浏览器控制台就会抛出异常。

同源策略带来的限制

有了同源策略后,我们日常开发中哪些行为会受到限制呢?

  • Cookie、LocalStorage、IndexDB 不同源无法共享,访问受限。
  • DOM video、audio、canvas、iframe 等DOM元素,不同源无法获取。
  • XHR/Fetch 请求 不同源情况下,浏览器发起的请求会被拦截。

什么是 CORS

上面讲到不同源就会报错,那怎么与不同源的服务器进行交互呢?接下来 CORS 就要登场了。

CORS 是一个W3C标准 全称为 “跨域资源共享”(Cross-origin resource sharing),它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求。

两种请求方式

解决跨域问题之前,我们要先知道一个事情,浏览器发出请求分为 简单请求非简单请求

那什么是简单请求呢?

满足以下两个条件的请求就是简单请求:

  1. 请求方法是以下三种方法之一:
    • HEAD
    • GET
    • POST
  2. HTTP的头信息不超出以下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencoded(表单提交)、multipart/form-data(文件上传)、text/plain(文本)

那什么是非简单请求呢?

简单请求之外的请求就是非简单请求,比如请求方法是 PUT 或者 DELETE,或者 Content-Typeapplication/json

OPTIONS 预检请求

当我们非同源情况下,发出请求时,浏览器会先发出一个 OPTIONS 请求,这个请求叫做 预检请求。用来检测服务器是否允许跨域请求。

只有预检请求通过后,才会发出真正的请求。

什么时候才会发送预检请求

是不是每次产生跨域都会发送预检请求呢?当然不是。

服务器响应头中设置 Access-Control-Max-Age 字段,表示预检请求的有效期,单位为秒。在有效期内,浏览器无需再次发出预检请求。

跨域请求头

当产生跨域时,浏览器会在请求头中添加 Origin 字段,表示请求来自哪个源。

服务端 CORS

前面说这么多,马上进入正题,如何配置服务端来解决跨域问题呢?

答案:服务端在response的header中配置以下字段:

  1. Access-Control-Allow-Origin 字段,表示允许哪些源进行跨域请求。如果与请求头中的 Origin 字段匹配,则允许跨域请求。
// 允许所有源进行跨域请求
res.header("Access-Control-Allow-Origin", "*");
// 或者 允许指定源进行跨域请求
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
  1. Access-Control-Allow-Methods 字段,表示允许哪些请求方法进行跨域请求。
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  1. Access-Control-Allow-Headers 字段,表示带有哪些请求头的请求可以进行跨域请求。
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");

跨域认证

到此,我们解决了跨域问题,但是还有一个问题,有些场景我们需要携带 Cookie去请求,那这个问题如何解决呢?

第一步:前端请求中做如下配置:

  • 如果使用fetch请求,需要设置 credentialsinclude
fetch('http://localhost:3000', {
    
    
  method: 'GET',
  credentials: 'include'
})
  • 如果使用xhr请求,需要设置 withCredentialstrue
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 去请求了。

完结撒花,你又进步了一点点。

ᕦ( •̀∀•́)ᕤ

猜你喜欢

转载自blog.csdn.net/SmileLife123/article/details/133045583