若请求的url的协议、域名、端口中的任意一个与当前的url不一样,即为跨域请求。跨域
跨域请求使得页面体验更好,但同时也带来了安全隐患。常见的一种网络攻击叫CSRF(Cross-site request forgery)。它的攻击原理大体以下:浏览器
基于CSRF等安全隐患,浏览器会限制从脚本发出的跨域请求,虽然安全性更高,页面体验却差了。因而W3C推出了一种跨域的访问验证的机制,即CORS,这种机制支持跨域请求,且跨站数据传输更安全。安全
CORS验证机制须要客户端和服务的协同处理。服务器
浏览器会对全部跨域请求进行验证,分为简单请求验证处理和预检请求验证处理。那么对应的就有简单请求和非简单请求之分。cookie
简单请求网络
若一个请求同时知足如下两个条件,那么则为简单请求。app
对于简单请求,浏览器直接发送该请求,在同一个请求中做跨域验证。怎么验证呢?在请求头上附上Origin属性,代表这是一个跨域请求。服务器接到请求,根据设定的跨域规则来验证,验证经过,返回Access-Control-Allow-Origin等以Access-Control-开头的响应头以及请求的资源,不然返回403状态码,且不会返回请求的资源。fetch
非简单请求网站
不为简单请求的跨域请求均为非简单请求。url
非简单请求的跨域验证经过一个预检请求来验证,即在发送一个正式的跨域请求以前,发送一个预检请求,用来检查当前网页所在的域名是否在服务器的许可名单中以及可以使用哪些请求方法,请求头字段。
预检请求
若预检请求经过验证,则响应字段里会包含以下字段:
Access-Control-Allow-Origin:值为请求头中的origin值或*
Access-Control-Allow-Methods: 代表可被支持的请求方法
Access-Control-Allow-Headers: 代表可被支持的头信息字段
Access-Control-Allow-Credentials: 当请求要求携带证书信息(例如cookie,受权信息等)验证,服务器端是否容许携带
Access-Control-Max-Age: 本次预检请求的有效期,单位为秒
若预检请求没经过验证,则响应字段里不会包含以Access-Control-开头的响应字段,且不会发送正式的跨域请求
正式的跨域请求
与简单请求同样,请求头中附带Origin
携带证书信息的请求
通常状况下,跨域请求不携带证书信息。但若请求的证书模式(credentials mode)被设为include,那么代表该请求须要携带证书信息。请求的证书模式可经过xmlHttpRequest.withCredentials = true设置或调用fetch([url],{mode:"include"})实现。
在简单请求及正式的非简单请求中,请求头附带证书信息,响应头回应:Access-Control-Allow-Credentials:true,并返回请求资源。
在预检请求中,请求头并不会附带证书,响应头会回应:Access-Control-Allow-Credentials:true。
有一点需注意:若服务器端赞成请求携带信息,则Access-Control-Allow-Origin不能为*,只能为请求头中指定的Origin值。