科技 · 实用指南
浏览器 CORS 失败?分别验证预检、实际响应与来源契约
浏览器请求可能在 API 调用前失败,也可能在 OPTIONS 成功后或携带凭据时失败。按证据顺序定位具体环节,不要靠猜测堆叠响应头。

当 curl 或 Postman 可用、浏览器 JavaScript 却报告 CORS 错误时,应把它视为一条请求链:先确认是否发出预检,再检查实际响应是否可读,最后核对凭据是否要求精确来源。
先捕获浏览器请求链
打开开发者工具的 Network 面板,保留日志并只复现一次。判断浏览器是否发送 OPTIONS、是否只发送实际请求,或在请求到达服务器前就停止。curl 或 Postman 成功只能说明该客户端能收到 HTTP 响应,不能证明浏览器会把跨来源响应暴露给脚本。
把 OPTIONS 预检当作独立交换
若存在 OPTIONS,分别查看请求与响应。请求通常含 Origin、Access-Control-Request-Method,以及必要时的 Access-Control-Request-Headers。响应必须允许精确来源、方法和所请求的请求头。200 或 204 都可能有效;重定向、认证挑战、网络失败或缺失允许头会阻止实际请求。
再独立检查实际响应
预检通过只允许浏览器发送真实请求。实际响应即使是 401、404 或 500,也要带匹配的允许来源头,脚本才能读取。如果正文可读但自定义响应头在脚本中不可见,应检查 Access-Control-Expose-Headers,而不是修改预检规则。
验证凭据与来源契约
携带 Cookie 或 HTTP 认证时,服务器不能返回 Access-Control-Allow-Origin: *,而要返回精确请求来源并设置 Access-Control-Allow-Credentials: true。预检本身不带凭据,因此要求 OPTIONS 先认证的中间件会提前阻断链路。CORS 头也不会绕过 SameSite 或第三方 Cookie 政策。
检查动态来源、缓存与中间件顺序
动态返回允许来源时增加 Vary: Origin,避免共享缓存把一个来源的响应复用给另一个来源。确认 CORS 中间件覆盖 OPTIONS 和错误路径,而非只在认证或成功路由后运行。应以已部署服务的 Network 结果为准。
使用停止分支表
既无 OPTIONS 也无实际请求,先查 URL、混合内容、扩展、DNS 或网络层。只有 OPTIONS 则修预检;两者都有但脚本不可读,则查实际响应的允许来源与凭据头;正文可读但自定义头不可见,则只暴露应用需要的响应头。
