一、CORS
CORS全称Cross-Origin Resource Sharing
,是HTML5规范定义的如何跨域访问资源。
Origin(本域)表示浏览器当前页面的域。当JavaScript向外域发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin
是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。
上面这种跨域请求,称之为“简单请求”。若请求满足所有下述条件,则该请求可视为“简单请求”:
1.使用下列方法之一
GET
HEAD
POST
2.Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为
Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Data
Viewport-Width
Width
3.Content-Type
的值仅限于下列三者之一
text/plain
multipart/form-data
application/x-www-form-urlencoded
4.请求中的任意XMLHttpRequestUpload
对象均没有注册任何事件监听器
XMLHttpRequestUpload
对象可以使用XMLHttpRequest.upload
属性访问
5.请求中没有使用 ReadableStream
对象
二、非简单请求
对于PUT、DELETE以及其他类型(如application/json
的POST请求),在发送AJAX请求之前,浏览器会先发送一个OPTIONS
请求(称为preflighted
请求)到这个URL上,询问目标服务器是否接受:
1 | OPTIONS /path/to/resource HTTP/1.1 |
服务器必须响应并明确指出允许的Method:
1 | HTTP/1.1 200 OK |
浏览器确认服务器响应的Access-Control-Allow-Methods
头确实包含将要发送的AJAX请求的Method,才会继续发送AJAX,否则,抛出一个错误。
三、Access-Control- 参数
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true
,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie,删除该字段即可。
(2.1)withCredentials 属性
如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials
字段;另一方面,开发者必须在AJAX
请求中打开withCredentials
属性。
1 | let xhr = new XMLHttpRequest(); |
否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。
但是,如果省略withCredentials
设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials
。
注:如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie
也无法读取服务器域名下的Cookie。
(3)Access-Control-Expose-Headers
该字段可选。CORS请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定。
四、什么情况下存在跨域问题
1 | 1、由 XMLHttpRequest 或 Fetch 发起的跨域 HTTP 请求 |
五、nginx配置例子
1 | location / { |