OPTIONS请求返回405或空响应,因Nginx默认不处理该方法,且add_header不加always参数时在return 204响应中不生效,导致CORS头缺失;应显式配置if拦截并为所有CORS头添加always标志。

为什么 OPTIONS 请求总返回 405 或空响应
因为 Nginx 默认不处理 OPTIONS 方法,遇到未显式配置的 OPTIONS 请求时,会直接走 fallback 流程——若 location 中没定义如何响应,就可能返回 405 Method Not Allowed,或者因 proxy_pass 后端不支持而透传失败,导致空体 + 502。
关键点在于:OPTIONS 是预检请求,浏览器只看响应头和状态码,不要求有 body;但 Nginx 的 add_header 指令默认不作用于 return 响应,所以必须加 always 参数,否则 return 204 时 CORS 头全丢失。
-
add_header必须带always标志,例如:add_header 'Access-Control-Allow-Origin' 'https://fe.example.com' always; - 不能只靠
if ($request_method = 'OPTIONS') { return 204; },否则所有 CORS 头都不生效 - 如果用了
proxy_pass,又没拦截OPTIONS,后端返回 404/405 就会暴露给浏览器,触发跨域拦截
add_header 的 always 参数到底要不要加
要加。不加 always,add_header 只对 2xx/3xx 响应生效;而 return 204 属于 2xx,看似没问题——但实测中,Nginx 在 return 分支里会跳过大部分 header 注入逻辑,除非显式声明 always。
尤其当配置里混用 proxy_pass 和 if 判断时,always 是唯一能确保预检响应带全 CORS 头的方式。
- 错误写法:
add_header 'Access-Control-Allow-Origin' '*';(return 204时头全丢) - 正确写法:
add_header 'Access-Control-Allow-Origin' '*' always; - 所有涉及 CORS 的
add_header行都应补上always,包括Access-Control-Allow-Methods、Access-Control-Allow-Headers等
Access-Control-Allow-Origin 设为 * 还是具体域名
取决于是否需要携带凭证(如 Cookie、Authorization header)。如果前端代码里写了 credentials: 'include',那么 Access-Control-Allow-Origin 就不能是 *,否则浏览器直接拒绝响应。
更麻烦的是:Nginx 的 add_header 不支持变量插值(如 $http_origin)用于动态白名单,除非你启用 map 模块提前映射。
- 开发环境可临时用
*,但上线前必须改掉 - 生产环境建议用
map实现白名单:map $http_origin $cors_origin { https://fe.example.com https://fe.example.com; https://staging.fe.example.com https://staging.fe.example.com; default ""; },再用add_header 'Access-Control-Allow-Origin' $cors_origin always; - 如果
$cors_origin为空,Nginx 不会发该 header,避免误配*导致凭证失效
proxy_pass 场景下 OPTIONS 请求怎么不穿透到后端
当你用 proxy_pass 把 /api/ 转发到后端时,Nginx 默认会把所有方法(包括 OPTIONS)原样转发。但多数后端(如 Express、Spring Boot)不处理预检,或返回 404,结果就是浏览器收不到合法 CORS 响应。
解决办法不是让后端扛,而是由 Nginx 在入口层截断并响应预检——这比改后端代码快,也更可控。
- 在
location /api/块内,先写if ($request_method = 'OPTIONS') { ... return 204; },且所有add_header都带always - 确保
if块在proxy_pass之前,否则会被跳过 - 别用
rewrite ^(.*)$ $1 break;类操作干扰$request_method判断
最易被忽略的一点:Nginx 的 if 是伪指令,嵌套层级和执行顺序很敏感;add_header 的作用域是 location 级,但只有加 always 才能突破 return 的限制。配完务必用 curl -I -X OPTIONS http://yourdomain.com/api/test 验证响应头是否齐全,别只信浏览器控制台。


















