CORS
# 介绍
CORS:Cross-Origin Resource Sharing(跨源资源共享/跨域资源共享),是一种允许当前域的资源被其他域的脚本请求访问的机制,通常由于同域安全策略浏览器会禁止这种跨域请求。
CORS 和代理转发应该是目前使用最多的解决跨域的方案。
# CORS请求
CORS 请求可以分为 简单请求 和 非简单请求。
# 简单请求
浏览器发现是简单请求,就会自动在头信息之中,添加一个origin
字段。服务端收到请求后会检测 origin
是否符合要求,如果符合,则返回Access-Control-Allow-Origin
,否则抛出错误。
请求报文
GET /resources/public-data/ HTTP/1.1
Host: bar.other
Origin: http://foo.example
...
1
2
3
4
2
3
4
响应报文
HTTP/1.1 200 OK
Server: Apache/2.0.61
Access-Control-Allow-Origin: http://foo.example
...
1
2
3
4
2
3
4
符合以下所有要求的请求被称为简单请求:
- 使用下列方法之一:
- GET
- HEAD
- POST
- 除了被用户代理自动设置的首部字段(例如 Connection ,User-Agent)和在 Fetch 规范中定义为禁用首部名称的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:
- Accept
- Accept-Language
- Content-Language
- Content-Type (限于这三者:text/plain、multipart/form-data、application/x-www-form-urlencoded)
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
- 请求中没有使用 ReadableStream 对象。
从上面的条件可以看出,如果项目设置了 content-type: application/json;charset=utf-8
,那相关的请求都不是简单请求了。
简单请求不会触发CORS预检请求。
# 非简单请求
与简单请求相反的就是非简单请求,也就是"需预检的请求"。它要求必须首先使用OPTIONS
方法发起一个预检请求到服务器,让服务器知道是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
也就是说除了简单请求外,设置了自定义header、不在范围内的content-type 等这些,都是预检请求,都会先发送一个
option
请求给服务器,服务器再进行判断是否允许,如果不允许,则抛出错误。
# HTTP首部字段
从非简单请求的流程图可以看出,HTTP请求与HTTP响应的首部字段部分是对应的,通过请求和响应实现了控制。
# 请求首部字段
首部字段 | 说明 | 预检请求 | 实际请求 |
---|---|---|---|
Origin: http://foo.example | 预检请求或实际请求的源站(服务器名称) | ✅ | ✅ |
Access-Control-Request-Method: POST | 将实际请求所使用的 HTTP 方法告诉服务器 | ✅ | ❌ |
Access-Control-Request-Headers: X-My-Custom-Header | 将实际请求所携带的首部字段告诉服务器 | ✅ | ❌ |
# 响应首部字段
首部字段 | 说明 | 预检请求 | 实际请求 |
---|---|---|---|
Access-Control-Allow-Origin: http://foo.example | * | 允许访问该资源的外域 URI | ✅ | ✅ |
Access-Control-Expose-Headers: X-My-Custom-Header | 让服务器把允许浏览器访问的头放入白名单 | ✅ | ✅ |
Access-Control-Allow-Credentials: true | 是否允许浏览器读取response的内容,false则不会返回数据 | ✅ | ✅ |
Access-Control-Allow-Methods: POST,GET | 实际请求所允许使用的 HTTP 方法 | ✅ | ✅ |
Access-Control-Allow-Headers: X-My-Custom-Header, x-Token | 实际请求中允许携带的首部字段 | ✅ | ✅ |
Access-Control-Max-Age: 86400 | preflight请求的结果能够被缓存多久(单位:秒) | ✅ | ❌ |
# CORS流程图
CORS的完整请求可以用以下流程图表示。
- Invalid CORS 对应的状态码是:
403
。 - 预检请求(OPTIONS)成功对应的状态码是:
204
。(204: 请求成功,但body没有数据返回)