Skip to content

预检 OPTIONS

简单请求

根据 CORS 规范,一个请求必须同时满足以下三个条件才会被视为**“简单请求”**(不触发预检):

  1. 方法限制:仅限 GETPOSTHEAD
  2. Content-Type 限制:仅限 application/x-www-form-urlencodedmultipart/form-datatext/plain
  3. 请求头限制:只能包含“受保护”的头部,如 AcceptAccept-LanguageContent-Language 等。

任何自定义请求头或不符合CORS 简单请求安全列表的标准请求头都会导致浏览器认为该请求具有“潜在风险”

CORS 简单请求安全列表:

请求头 (Header)限制条件与说明
User-Agent-
Referer-
Host-
Connection-
Accept告知服务器客户端可以处理的内容类型。通常无特殊限制。
Accept-Language告知服务器客户端理解的语言。通常无特殊限制。
Content-Language告知服务器请求体所使用的语言。通常无特殊限制。
Content-Type仅限: 1. application/x-www-form-urlencoded 2. multipart/form-data 3. text/plain
Range仅限简单的字节范围值(例如 bytes=128-255)。
Viewport-Width视口宽度(客户端提示,较少手动设置)。
Width图像宽度(客户端提示,较少手动设置)。
DPR屏幕像素比(客户端提示)。
Save-Data告知服务器客户端是否开启了节流模式。

在实际开发中,几乎一定会触发预检:

行为原因
携带 Token设置了 Authorization 头部。
发送 JSON设置了 Content-Type: application/json
自定义 Header比如公司规范要求的 X-App-VersionX-Request-Id
非简单方法使用 PUTDELETEPATCH 等方法。

预检请求

浏览器发送非简单请求时,会认为请求“可能不安全”,因此在发送非简单请求前会先发送预检请求:

js
OPTIONS /api/xxx

预检请求头会附带即将发送的非简单请求的相关信息:

yaml
# 非简单请求的源
Origin: http://www.a.com
# 非简单请求的请求方法
Access-Control-Request-Method: PUT
# 不符合非简单请求的请求头key,如果没有,将不发送
Access-Control-Request-Headers: Authorization

预检响应

浏览器通过检查 预检请求(OPTIONS)的响应头 来判断服务器是否允许这次跨域请求。

yaml
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH
Access-Control-Allow-Headers

如果预检通过,浏览器才会真正发实际请求。预检不通过浏览器将会报CORS错误

预检请求缓存

浏览器通常会 缓存预检请求 的结果,这样可以减少不必要的预检请求。具体来说,浏览器会缓存 CORS 预检请求的响应结果,默认缓存时间为 5分钟,你可以在响应头中使用 Access-Control-Max-Age 来设置缓存时间。

js
Access-Control-Max-Age: 3600

如果预检请求已经被发送并成功响应,在缓存有效期内,浏览器就不会每次都发出预检请求,而是直接发送实际请求。这是为了减少网络开销和提高性能。

调试

如果需要停用预检请求缓存,你可以在浏览器调试工具中勾选停用缓存