夸源资源共享是(CORS) 是一种基于HTTP的头机制,该机制可以允许浏览的跨域访问服务器的资源,服务通过设置响应头Access-Control-Allow-Origin来表示除了他自身之外的其他的源( 协议,域名,端口号)。
此外,CORS还有一种机制来检查是服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求(OPTIONS)。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
1. 什么是“预检”请求?
夸源资源共享标准新增了一组HTTP首部字段,允许服务器声明那些源站通过浏览器能够有权限访问那些资源.
规范要求,对于那些有可能对服务器产生的副作用的HTTP请求方法,特别是GET以外的请求,或者那些搭配MIME类型的POST请求,浏览器必须首先使用OPTIONS方法发送一个预检请求,从而获知服务器是否允许真实请求,服务器允许后,才发送实际的请求。
同时在预检请求的返回中,服务器也可以告诉浏览器,是否携带身份认证。
1.为什么要有设置“预检”请求?
简单来讲,避免浏览器带来的副作用。先排除先遣部队躺一波雷,如果能够安全返回,那么大部队就可以放心的出击,如果大部队直接上,可能任务完成了,但是回不来了,这就是一个失败的任务。
出于安全考虑,浏览器发出的网络请求会遵循同源策略,想XMLHttpRequest和Fetch都会遵守同源策略,一般来讲,浏览器显示跨域请求的方式一般有两种:
- 浏览器限制发起的跨域的请求。
- 跨域请求可以发起,但是返回的结果会被浏览器拦截。
大多数浏览器都是采用第二种方案,如果没有预检请求的话,就会产生一种情况,对于一些对服务器产生副作用的操作,请求可以正常发出并被服务器处理,可能会服务器中的数据变更,比如修改静态资源或者修改数据库中的数据,但是响应数据却被浏览器拦截了,这就是一次失败的请求。
为了避免这种情况,规范要求对于可能对服务器造成副作用的HTTP请求方法,浏览器必须首先使用OPTIONS方法发送一个预检请求,从而获知服务器是否允许真实请求,服务器允许后,才发送实际的请求。
2.什么情况下会发送“预检”请求?
在跨域资源访问的时候,浏览器会将请求方式分为简单请求和非简单请求,对于非简单请求,浏览器会发送一个“预检请求”,在预检中,浏览器发送的头部,标识有HTTP方法和真实请求会用到的头。
满足下方条件的请求称为简单请求,不会触发options。
- 请求方式:
GET POST HEAD - 请求头:
Accept Accept-Language Content-LanguageContent-Type告诉服务器我要发送什么类型的数据,仅限于一下三者之一- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
application/jsonapplication/xml
DPR:客户端设备的像素比DownLink:是NetworkInformation接口的一个只读属性,返回以 Mb/s 为单位的有效带宽,并保留该值为 25kb/s 的最接近的整数倍。该值基于最近监测的保持活跃连接的应用层吞吐量,排除了到私有地址空间的连接。当缺少最近的带宽测量数据时,该属性由底层连接技术属性决定。Save-Data:是NetworkInformation接口的只读属性, 如果用户设备上设置了减少数据使用的选项时返回true.Viewport-Width:可视窗口的大小。- 请求中没有使用
ReadableStream对象。 - 请求中的任意
XMLHttpRequestUpload对象均没有注册任何事件监听器;XMLHttpReq uestUpload对象可以使用XMLHttpRequest.upload属性访问。
不满足上述条件的跨域都被称为非简单网络请求,都会触发options请求,因为浏览器不确定这些请求会不会对服务器造成不可预知的影响,同时在发出请求的时候,需要服务器返回响应的头部,才可以进行真实的请求。
-
使用
Put、Delete、Trace、Connect请求方法。- 服务器需要返回
Access-Control-Allow-Methods: POST, GET, OPTIONS。
- 服务器需要返回
-
使用了自定义的HTTP头部或不在上面范围的头部,
setRequestHeader('X-PINGOTHER', 'pin gpong')。- 服务器需要返回
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type。
- 服务器需要返回
-
contentType不符合三者之一。setRequestHeader('Content-Type', 'application/xml')。- 服务器需要返回
Access-Control-Allow-Headers: Content-Type。
-
携带了身份信息的请求,
withCredentials = true。- 服务器需要返回
Access-Control-Allow-Credentials: true。
- 服务器需要返回
-
优化点:
Access-Control-Max-Age该字段可选,用来指定本次预检请求的有效期,单位为秒,在此期间,不用发出另一条预检请求。