一文弄懂CORS跨域原理

发布时间 2023-05-05 21:48:59作者: pwindy

1.前言

由于同源策略的存在,导致我们在跨域请求数据的时候非常麻烦,首先阻挡我们的所谓同源到底是什么呢?所谓同源就是浏览器的一个安全机制,不同源的客户端脚本没有在明确授权的情况下,不能读写对方额资源。由于存在同源策略的限制,而又有需要跨域的业务,所以就有了CORS的出现。

我们都知道,jsonp也可以跨域,那为什么还要使用CORS呢

  • jsonp只可以使用GET方式提交
  • 不好调试,在调试失败的时候不会返回任何状态码
  • 安全性,万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制了。那么结果是什么?所有调用这个jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下...所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。

2.开始CORS

CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),它允许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持,整个CORS通信过程,都是浏览器自动完成不需要用户参与,对于开发者来说,CORS的代码和正常的ajax没有什么差别,浏览器一旦发现跨域请求,就会添加一些附加的头信息。

CORS这么好吗,难道就没有缺点吗?

答案肯定是NO,目前所有最新浏览器都支持该功能,但是万恶的IE不能低于10

3.简单请求和非简单请求

浏览器将CORS请求分成两类,简单请求和非简单请求。

3.1.简单请求

凡是同时满足以下两种情况的就是简单请求,反之则非简单请求,浏览器对这两个请求的处理不一样。

  • 请求方法是以下三种方法之一
  • HEAD
  • GET
  • POST
  • HTTP的头信息不超出以下几种字段
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

对于简单请求来说,浏览器之间发送CORS请求,具体来说就是在头信息中,增加一个origin字段,如下:

上面的头信息中,Origin字段用来说明本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源不在允许范围之内,服务器就会返回一个正常的HTTP回应,然后浏览器发现头信息中没有包含Access-Control-Allow-Origin字段,就知道出错啦,然后抛出错误,反之则会出现这个字段,如下:

  • Access-Control-Allow-Origin:这个字段是必须的,表示接受那些域名的请求(*为所有)
  • Access-Control-Allow-Credential:该字段可选,表示是否可以发送cookie
  • Access-Control-Expose-Headers:该字段可选,XHMHttpRequest对象的方法只能够拿到六种字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他的需要,使用该字段指定。

如果想要连带Cookie一起发送,是需要服务端和客户端配合的。

3.2.非简单请求

非简单请求则是不满足上边的两种情况之一,比如请求的方式为PUT,或者请求头包含其他的字段

非简单请求的CORS请求是会在正式通信之前进行一次预检请求。

浏览器先询问服务器,当前网页所在的域名是否可以请求您的服务器,以及可以使用哪些HTTP动词和头信息。只有得到正确的答复,才会进行正式的请求。

由于上面的代码使用的是PUT方法,并且发送了一个自定义头信息,所以是一个非简单请求,当浏览器发现这是个非简单请求的时候,会自动发出预检请求,看看服务器可不可以接收这种请求

“预检”的HTTP头信息(请求头)

 “预检”使用的请求方法是OPTIONS,表示这个请求是用来询问的。

预检请求后的回应,服务器收到的“预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段后,确认允许跨源请求,就可以做出回应。

预检的响应头

如果浏览器否定了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS的头相关信息。这时,浏览器就认定服务器不允许此次访问,从而抛出错误。

预检之后的请求(请求头)

当预检请求通过后,发出正经的HTTP请求,还有一个就是一旦通过了预检请求,第二次请求的时候就会是简单请求,会有一个Origin头信息字段。

通过预检之后,浏览器发出请求

参考--- https://mp.weixin.qq.com/s/vxjMt4b49aUB3UJNyZrdDg