大家好,我是前端西瓜哥。
因为同源策略(Cross-Origin Policy)的存在,浏览器在一个域名下发送另一个域名的 Ajax 请求时,返回的数据通常会被浏览器拦截,让开发者无法拿到返回结果。
这里说 “通常”,是因为浏览器额外提供了一种可以正常使用 Ajax 请求非同源域名接口的机制,也就是我们接下来要说的 跨源资源共享(CORS, Cross-Origin Resource Sharing)。
CORS 会在上图中的第三步中发挥作用。
简单来说,就是请求 b.com 的 HTTP 响应头字段中的一些头字段符合一定规则,返回数据就不会被浏览器拦截,请求者能正常获得返回数据。
简单请求和非简单请求是浏览器发出跨域请求的 两种不同的请求方式,我们来了解一下。
发送的请求符合下面的所有情况,就属于简单请求。
(还有一些更多的琐碎的细节,比如脚本设置、特定浏览器相关的,这里不展开,具体可以查阅官方文档)
可能你会对这个规则的设计很感兴趣,其实它是为了 向后兼容,兼容一些之前没有 Ajax 时就可以发送的跨域请求,比如 form 元素能够产生的请求。
点击表单下的提交按钮,页面跳转然后发送请求。这种写法非常古老了,因为会自动跳转页面且不能拿到返回数据执行下一步的操作,实际开发基本上不会使用了
CORS 机制下,HTTP 响应头字段需要使用头字段
Access-Control-Allow-Origin,将它的值设置为:
另外,如果请求中携带了身份信息,也就是 Cookie,不能使用 *,而需要指定具体域名。
这样设置后,我们就能正常地拿到其他域名接口返回的数据了。
下面我们再看看非简单请求。
不符合简单请求规定条件的请求,就是 非简单请求。
对于简单请求,为了兼容,浏览器会直接将请求发出去。但非简单请求没有兼容的需要,所以浏览器给它加上了严格的复杂机制。
在发出真正的请求前,浏览器会先发一个 OPTION 请求来探探路,这个请求称为 预检请求(preflight)。
浏览器发送的请求,会额外带下以下请求头字段:
下面是服务端的回合。
服务端拿到了足够多的请求方信息,然后就可以考虑是否允许跨域了。
服务端的响应头字段可以携带上以下字段:
浏览器拿到这些字段后,就会进行对比,如果不符合规则,那么真正的跨域请求将不会发送。如果不符合,接下来就会发送真正的跨域请求。
需要注意的是,真正的请求和简单请求一样,需要提供Access-Control-Allow-Origin 头字段,否则依旧拿不到返回数据。
CORS 真正的形态是非简单请求,它不会立即发送真正的请求,而是额外发送 OPTION 方法的预检请求,让服务端来决定是否允许即将发送的请求。
简单请求是向后兼容的妥协产物,它其实直接向目标发起了真正请求,只是浏览器可能会将返回的数据拦截掉,如果响应头没有设置正确的
Access-Control-Allow-Origin 的话。