CORS


2021-03-09 上次更新时间:4/29/2022, 9:34:08 AM 0

# 介绍

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

响应报文

HTTP/1.1 200 OK
Server: Apache/2.0.61
Access-Control-Allow-Origin: http://foo.example
...
1
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没有数据返回)
上次更新时间: 4/29/2022, 9:34:08 AM