要理解CORS需要先了解同源策略
同源策略
同源策略是一个重要的安全策略,它是浏览器最核心最基本的安全功能。
它限制web应用程序只能从加载应用程序的同一个域请求HTTP资源。
当向不同的域请求HTTP资源时就发生了跨域,默认请情况下浏览器会阻止跨域的请求。
那如何判断是否同源呢?
如果两个URL的协议,端口和主机都相同的话,则这两个URL是同源。
以下所有资源都具有相同的来源:
http://example.com/
http://example.com:80/
http://example.com/path/file
每个url都有相同的协议,主机和端口号
以下每个资源都与其他的不同源:
http://example.com/
http://example.com:8080/
http://www.example.com/
https://example.com:80/
https://example.com/
http://example.org/
http://ietf.org/
所以所谓的同源策略简单的理解就是,打开某个页面后,这个页面上的ajax请求默认只能向和页面同源的url发送http请求。同源策略固然保证了安全,但同时也限制了应用的灵活性,所以出现了CORS.
什么是CORS
CORS是一个W3C标准,全称是"跨域资源共享"(cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
CORS原理
跨域请求
浏览器将跨域请求分为两类:简单请求和非简单请求。
只要同时满足一下两个条件,就属于简单请求:
- 请求方法是一下三种方法之一:
- head
- get
- post
- http请求的头信息不超出以下几种字段:
- accept
- accept-language
- content-language
- Last-Event-ID
- Content-Type的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
简单请求CORS步骤
对于简单请求CORS的基本流程如下:
第一步:客户端(浏览器)请求
当浏览器发出跨域请求时,该浏览器会添加一个包含当前源(协议,主机和端口)的Origin
头。
第二步:服务器响应
在服务器,当服务器看到Origin
头并想要允许访问时,就需要在响应中加入一个Access-Control-Allow-Origin
响应头来指定请求源(例如加入*
表示允许任何源)
第三步:浏览器接受响应
当浏览器看到带有相应Access-Control-Allow-Origin
响应头的响应时,即允许与客户端网站共享响应数据。否则抛出CORS异常。
注意同源策略只是浏览器遵守的规则,使用别的工具进行请求不会遵循同源策略的影响。
复杂请求CORS步骤
第一步:发送预检请求
浏览器会根据需要创建预检请求。该请求是一个options
请求,会在实际请求消息之前被发送。
预检请求中关键请求头是origin
表示请求来自哪个源。除了origin
字段,预检请求头的信息还包含两个特殊字段。
-
access-control-request-method
该字段是必须的,用来列出接下来的CORS请求会用到哪些HTTP方法,上面图片中的是PATCH
-
access-control-request-headers
这个字段是一个逗号分隔的字符串,指定接下来的CORS请求还会携带哪些额外的字段,上面图片中的是content-type
第二步:响应预检请求
服务器收到预检请求后,检查origin
,access-control-request-method
,access-control-request-headers
字段后,就可以返回响应。
响应中的access-control-allow-origin
字段表示允许跨域的源,*表示允许任意跨域请求。其他CORS相关响应头如下:
-
Access-Control-Allow-Methods
逗号分隔的一个字符串,表明服务器允许的跨域请求方法
-
Access-Control-Allow-Headers
逗号分隔的一个字符串,表明服务器支持的头字段
-
Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上图中的有效期是一天(86400秒),在此期间不用发出另一条预检请求。
注意:如果服务器否定了预检请求,也会返回一个正常的HTTP响应,但是不包含任何CORS相关的响应头。
第三步:发送跨域请求
一旦服务器通过了预检请求,以后每次浏览器正常的CORS请求,就跟简单请求一样,会有一个origin
头字段。服务器的回应,也会有一个access-control-allow-origin
头信息字段。
cookie跨域
出于隐私原因,CORS请求默认不带cookie。如果想要在使用CORS时发送cookie,就需要发送请求是携带cookie并且服务器也同意。
请求
ajax请求需要打开withCredentials
属性才可以携带cookie:
const request = axios.create({
baseURL: 'http://127.0.0.1:8000',
timeout: 5000,
withCredentials: true // 设置为true 跨域时会携带cookie
})
响应
如果要接受cookie跨域,access-control-allow-origin
就不能设置为星号,必须指定明确,并且响应头中必须包含字段Access-Control-Allow-Credentials
,值为true
。
同时cookie依然遵循同源策略,只有服务器指明的域名的cookie才会上传。
欢迎来到testingpai.com!
注册 关于