CORS的通讯流程:简单请求、非简单请求

209 阅读3分钟

这是我参与更文挑战的第6天,活动详情查看: 更文挑战

简单请求

  1. 浏览器:发现为跨源请求,直接发出CORS请求,自动在头信息中,添加一个Origin字段
GET /cors HTTP/1.1
Origin: http://api.example.com
Host: api.example.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

# Origin字段作用:说明请求来源(协议、域名。端口),服务器根据其值决定是否同意本次请求
  1. 服务器:根据Origin字段中的信息:
    • 若不在许可范围内,返回正常HTTP回应。浏览器发现不包含CORS的特定字段,抛出错误并被捕获。
    • 若在许可范围内,返回回应中头信息包含: Access-Control-Allow-Origin 字段(必须)、Access-Control-Allow-Credentials 字段(可选)、Access-Control-Expose-Headers 字段(可选)
Access-Control-Allow-Origin: http://api.example.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
                                # getResponseHeader('FooBar')可以返回FooBar字段的值

# 三个字段均以Access-Control-开头
# Access-Control-Allow-Origin(必须):Origin字段的值,或者为 *(表示任意域名的请求均接受)
# Access-Control-Allow-Credentials(可选):布尔值,表示是否允许发送Cookie,仅以下两种情况
#                                        - 有该字段,值为true:浏览器可以携带Cookie发送请求
#                                        - 无该字段:服务器不要浏览器发送 Cookie(默认)
# Access-Control-Expose-Headers(可选):指定浏览器 getResponseHeader() 方法可以拿到的字段,其默认仅能够拿到6个服务器返回的基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma,其余字段需在此指定说明

非简单请求

  1. 浏览器:发现CORS非简单请求,发送“预检”请求,询问是否在服务器许可名单中,及可使用的HTTP动词、头信息字段。
OPTIONS /cors HTTP/1.1
Origin: http://api.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

# 使用OPTIONS方法,表示这个请求是用来询问的
# 头信息中的关键字段是Origin,表示请求来自哪个源。
# 除了Origin字段,还包括两个特殊字段:
#     1. Access-Control-Request-Method(必须):列出浏览器的 CORS 请求会用到哪些 HTTP 方法,上例是PUT。
#     2. Access-Control-Request-Headers(可选):该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段,上例是X-Custom-Header
  1. 服务器:验证是否运行跨源请求
    • 否定:返回一个正常的 HTTP 回应,其中无没有任何 CORS 相关的头信息字段,或者明确表示请求不符合条件。
    • 同意:返回包含Access-Control-Allow-Origin等字段的信息
# 否定返回:
OPTIONS http://api.example.com HTTP/1.1
Status: 200
Access-Control-Allow-Origin: http://api.no.com
Access-Control-Allow-Method: POST
# 同意返回
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

# Access-Control-Allow-Methods(必须):逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次“预检”请求。
# Access-Control-Allow-Headers:如果浏览器请求包括Access-Control-Request-Headers字段,则该字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段。
# Access-Control-Allow-Credentials(可选):该字段与简单请求时的含义相同。
# Access-Control-Max-Age(可选):指定本次预检请求的有效期,单位为秒。在有效期内,不用发出另一条预检请求。
  1. 正式通讯:在有效期内,按简单请求的流程发送CORS请求