CORS 预检在浏览器发送请求之前检查许可
CORS 预检询问浏览器是否可以发送某个具体的跨源请求,内容包括发起页面的源、计划使用的方法和相关请求头名称。浏览器会先判断预检响应是否允许,再发送实际请求;已有有效预检缓存时,则可能省去这次询问。CORS 同时约束脚本能否读取实际响应。发送许可与响应读取是相互关联的两次检查,但任何一次都不能代替业务身份认证和权限控制。 预检由请求形式触发 源由协议、主机和端口组成,任一部分变化都可能使请求跨源。浏览器不会猜测服务器是否修改数据,再据此决定要不要预检。符合条件的 text/plain 类型 POST 可以直接发送;反而一个仅仅读取数据、却带有 Authorization 头的请求通常需要预检。方法、头部取值以及 Fetch 定义的其他条件共同决定请求是否属于安全列出的范围,“读取不用、写入必用”不是正确规则。 JSON POST 通常需要预检,因为 application/json 不是安全列出的内容类型。浏览器先向目标发出 OPTIONS,携带 Origin、值为 POST 的 Access-Control-Request-Method,以及包含 content-type 的 Access-Control-Request-Headers。这里发送的是未来头部的名称,不是其中可能包含的凭据值。服务器需要允许对应源、方法和相关字段,浏览器才会继续发送这一次实际请求。 两个响应都需要正确配置 受限接口应按完整源进行精确白名单匹配,并在 Access-Control-Allow-Origin 中返回一个允许的源。不能返回逗号分隔的源列表,也不能无条件照抄任意输入。公开给所有来源、且请求不带凭据的资源可以使用星号;携带凭据的访问则需要明确的源和 Access-Control-Allow-Credentials: true。浏览器自己的 Cookie 限制仍然独立生效,CORS 放行不会自动突破这些限制。 实际响应也必须包含适用的 CORS 字段,希望脚本能读取的错误响应同样如此。预检通过,并不能授权脚本读取一个后来缺少许可字段的响应。若返回内容或头部依赖 Origin,还应添加 Vary: Origin,让共享缓存区分不同来源的变体。Access-Control-Max-Age 控制专用预检缓存,并受到浏览器上限约束;不能仅靠普通 HTTP 缓存规则解释为什么某次请求没看到 OPTIONS。 ...