CORS 凭据请求排查:明确来源、预检与 Cookie
区分 OPTIONS 与实际响应,核对凭据请求所需的明确来源、允许方法和请求头,再通过允许来源与拒绝来源测试检查修复结果。
浏览器请求使用 credentials: include 时,Access-Control-Allow-Origin 必须返回允许的明确来源,不能为 *,响应还需 Access-Control-Allow-Credentials: true。Authorization 头与 Cookie 接收另有规则,不能仅凭这些头保证请求成功。
本指南涉及工具
现象
- 服务端返回 200,但浏览器控制台报 CORS 错误。
- curl/Postman 能读取响应,浏览器使用 credentials: include 时却无法读取。
- 不同来源下预检结果忽好忽坏。
原因
- 开启 credentials 时仍使用了通配 Origin。
- 动态回显 Origin 场景缺少 Vary: Origin,缓存错配。
- Allow-Headers/Allow-Methods 与前端真实请求不一致。
修复步骤
- 把 Origin 改为明确域名,或使用受控回显(不要直接 *)。
- 用生成器为一个固定允许来源生成响应头;它不实现动态白名单。服务端若按请求选择来源,需在服务端实现检查并设置 Vary: Origin。
- 检查整段请求/响应头,若走会话鉴权再联动核验 Set-Cookie 属性。
明确允许来源的响应头示例
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin常见问题
带凭据时能不能用 *?
不能,这是浏览器规范层面的硬限制。
什么时候必须加 Vary: Origin?
只要 Origin 是动态回显就必须加,避免缓存串值。
1. 把预检与实际响应分开检查
假设 https://app.example.com 向另一个 Origin 的 API 发送 POST,使用 Content-Type: application/json、Authorization 和 credentials: include。浏览器通常先发送 OPTIONS,说明 POST 和所需的非简单请求头;分别检查 OPTIONS 与后续 POST。
这个样例的预检需允许明确来源、POST,以及显式的 Content-Type、Authorization 头,并返回 Access-Control-Allow-Credentials: true。实际响应也需要来源与凭据响应头,OPTIONS 返回 204 并不代表 POST 一定可读。
2. 同时测试允许来源与未允许来源
使用可丢弃的测试接口,分别从白名单来源与不在白名单的来源发起浏览器请求。服务端不能直接回显任意 Origin。预期允许来源能读取响应,未允许来源拿不到让浏览器脚本读取响应的许可。
CORS 报错不证明请求从未到达或被服务端处理。部分请求无需预检,应用鉴权和 CSRF 防护也仍是独立任务;不要拿付款等有实际后果的接口做实验。
3. 再检查缓存与 Cookie 的实际决策
服务端按请求来源返回不同响应头时,设置 Vary: Origin,并确认 CDN 缓存尊重该字段。检查经过网关后的最终响应,重复或冲突的 Access-Control-Allow-Origin 也可能导致失败。
使用 Cookie 会话时,查看浏览器实际排除原因、作用域和凭据模式。SameSite=None; Secure 不能覆盖第三方 Cookie 阻止策略;curl 能显示头部,但不执行浏览器 CORS 与 Cookie 规则。