nginx 默认不在自动生成的502响应中执行add_header,必须通过error_page 502 = @cors_502配合命名location @cors_502,在其中用add_header ... always和return 502统一注入cors头并保留原始状态码。

当 Nginx 作为反向代理,后端服务不可用(如宕机、网络不通)导致返回 502 Bad Gateway 时,默认情况下 Nginx 不会执行 location 中的 add_header 指令——因为这些指令只在正常代理成功响应时生效,而 502 属于 Nginx 自身生成的错误响应,绕过了常规 header 注入逻辑。
让 502 响应也携带 CORS 头的核心方法
必须使用 error_page + 自定义 error location 的方式,将 502 显式重定向到一个内部 location,在那里统一添加跨域头并返回响应:
- 在对应
location块中添加:proxy_intercept_errors on;—— 启用拦截 Nginx 生成的错误页(如 502/503/504) - 添加:
error_page 502 = @cors_502;—— 把 502 重定向到名为@cors_502的命名 location - 在 server 或 http 块顶层定义该命名 location:
location @cors_502 {<br> add_header 'Access-Control-Allow-Origin' '$http_origin' always;<br> add_header 'Access-Control-Allow-Credentials' 'true' always;<br> add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;<br> add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;<br> return 502;<br>}
为什么不能只靠 add_header + always?
add_header ... always 确实能让 header 出现在多数成功响应中,但它不作用于 Nginx 自己生成的错误响应体(比如 proxy_pass 失败时的默认 502 页面)。Nginx 只有在使用 error_page 重写错误响应流程时,才会进入目标 location 并执行其中的 add_header 和 return。
配套建议:保持预检 OPTIONS 不受干扰
如果同时处理 OPTIONS 预检请求,要确保它不被 502 拦截逻辑覆盖:
- 把
if ($request_method = 'OPTIONS') { ... return 204; }放在proxy_pass之前 - 确保
error_page 502 = @cors_502写在同一个 location 内,且不与 if 块冲突 - 命名 location
@cors_502是内部跳转,不会触发新的路由匹配,安全可控
验证是否生效
可临时停掉后端服务,用 curl 模拟跨域请求:
curl -H "Origin: https://app.example.com" -I http://your-nginx/api/test
观察响应头中是否包含 Access-Control-Allow-Origin 和状态码是否为 502 —— 两者同时出现,说明配置已起效。











