nginx默认不在5xx响应中添加add_header,必须为每个头显式添加always参数才能确保x-frame-options、strict-transport-security、access-control-allow-origin等在500/502/503等错误响应中生效,且需在error_page指向的location及proxy_pass路径中分别配置。

后端返回 5xx 错误时,Nginx 默认不会在响应中添加你配置的 add_header,哪怕这些头写在 server 或 location 块里。结果就是:浏览器收不到 X-Frame-Options、Strict-Transport-Security 或 Access-Control-Allow-Origin,既影响安全策略生效,又导致跨域错误信息被拦截,前端无法读取真实错误内容。
必须为每个安全头显式加上 always
默认行为只对 2xx/3xx 状态码生效,5xx 完全被跳过。解决方式不是改逻辑,而是补参数:
add_header X-Frame-Options "DENY" always;add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;add_header Access-Control-Allow-Origin "*" always;add_header X-Content-Type-Options "nosniff" always;
注意:always 必须写在每行末尾、分号之前,且不能省略;漏掉任意一个,对应头在 500、502、503 等响应中就彻底消失。
特别注意 error_page 拦截后的 location 分支
如果你配置了自定义错误页,例如:
error_page 500 /50x.html;
那么 Nginx 实际返回的是 /50x.html 所在的 location 块处理的结果。这个新 location 若没重写 add_header ... always,所有安全头都会丢失。
正确做法是显式声明:
location = /50x.html {<br> root /usr/share/nginx/html;<br> add_header X-Frame-Options "DENY" always;<br> add_header Access-Control-Allow-Origin "*" always;<br>}
代理场景下,5xx 来自上游时的处理要点
当后端挂掉(如返回 502 Bad Gateway)或主动抛出 500,Nginx 默认只是透传响应,不会自动注入头——即使你配了 always,也只对它自己生成的响应生效。
此时关键在于:确保 add_header ... always 出现在能覆盖该响应路径的 location 块中。例如:
location /api/ {<br> proxy_pass http://backend;<br> add_header Access-Control-Allow-Origin "*" always;<br> add_header X-Content-Type-Options "nosniff" always;<br>}
这样,无论后端返回 200 还是 500,只要走这个 location,头都会带上。
验证是否真正生效
别等线上出问题才查。用 curl 主动触发 5xx 响应并检查头:
- 让后端临时返回 500(比如调用一个已宕机的服务)
- 或在测试 location 中加:
return 500 "Internal Server Error"; - 执行:
curl -I -H "Origin: https://example.com" https://your-domain.com/api/test - 确认响应中同时包含
HTTP/1.1 500和你期望的Access-Control-Allow-Origin、X-Frame-Options等头











