CORS 预检请求排查指南:OPTIONS、跨域头与网关配置一次讲清

“接口明明通,浏览器却报 CORS”是最常见的线上联调阻塞之一。多数问题不在业务逻辑,而在跨域头、代理层和预检缓存的细节。把排查顺序固定下来,可以大幅减少来回试错。

1. 先理解什么时候会触发预检

浏览器在下列情况会先发 `OPTIONS` 预检:

  • 方法不是简单方法(例如 `PUT`、`DELETE`)。
  • 请求头包含自定义头(例如 `Authorization`、`X-Trace-Id`)。
  • `Content-Type` 不是简单类型(例如 `application/json`)。

预检失败时,真正业务请求根本不会发出去,所以后端日志里可能看不到对应 `POST` 或 `PUT`。

2. 按“浏览器报错语句”定位配置缺口

常见报错基本能直接映射到缺失项:

  • `No 'Access-Control-Allow-Origin'`:服务端没回允许来源。
  • `Method ... is not allowed`:`Access-Control-Allow-Methods` 缺少对应方法。
  • `Request header field ... is not allowed`:`Access-Control-Allow-Headers` 未放行该头。
  • `credentials mode is include` 报错:使用了 Cookie,但 Origin 配置为 `*`。

先让报错和响应头逐项对齐,比“改一行试一次”更快。

3. 网关与应用层必须同口径

很多团队只在应用层加 CORS 中间件,却忽略了 Nginx/API Gateway。真实链路通常是:浏览器 -> CDN -> 网关 -> 服务。只要中间有一层吞掉或改写头部,前端仍会失败。

建议固定责任边界:要么统一在网关处理 CORS,要么网关透传并由应用层统一处理,避免双重配置互相打架。

4. Cookie 场景的三个硬条件

跨域带 Cookie(`credentials: include`)时,必须同时满足:

  1. `Access-Control-Allow-Credentials: true`
  2. `Access-Control-Allow-Origin` 不能是 `*`,必须是具体域名
  3. Cookie 端设置 `SameSite=None; Secure`

这三项缺任何一项,都会出现“本地能用、线上不稳定”问题。

5. 用预检缓存降低 OPTIONS 放大

高频接口如果每次都预检,会产生额外延迟与网关开销。可配置 `Access-Control-Max-Age` 缓存预检结果,但要兼顾安全与变更频率,通常从 600 秒到 3600 秒逐步评估。

先保证正确,再做缓存优化。错误的 CORS 配置缓存会把问题放大到整个用户群。

推荐排查流程(10 分钟版本)

  1. 浏览器 Network 面板确认是否发了 OPTIONS。
  2. 对照预检响应头,定位缺失字段。
  3. 检查网关是否覆盖或删除了 CORS 头。
  4. 检查 Cookie 场景是否满足三条件。
  5. 确认修复后再加 `Access-Control-Max-Age`。

这个流程跑通后,80% 的跨域问题都能在联调阶段解决,不会拖到发布窗口。