add_header 的 always 参数可强制响应头在所有状态码下发送;默认仅 2xx/3xx 生效,加 always 后如 X-App-Version、Strict-Transport-Security 等头在 4xx/5xx 错误时仍生效,用于调试、安全加固与前端容错。

在 Nginx 中,add_header 默认只在响应状态码为 2xx 或 3xx 时生效;遇到 4xx、5xx 等错误响应,头信息会被悄悄丢弃。而加上 always 参数后,就能强制让指定响应头**无论状态码是多少都发送出去**——这是调试、安全加固和前端容错的关键技巧。
为什么默认不发错误响应头?
Nginx 的设计逻辑是:只对“成功”或“重定向”类响应添加自定义头,避免干扰错误处理流程。比如你写了:
add_header X-App-Version "1.2.3";
当后端返回 502 Bad Gateway 时,这个头根本不会出现在响应里。前端拿不到版本号,监控系统也收不到上下文,排查问题就少了一条关键线索。
always 参数怎么用?语法很简单
只需在 add_header 指令末尾加上 always 关键字:
add_header X-App-Version "1.2.3" always; add_header X-Request-ID $request_id always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
注意:always 必须写在最后,不能加引号,也不能换行。它不接受变量(如 $status)动态控制,但可配合 map 或 if(谨慎使用)做条件判断。
这些场景离不开 always
- 错误页透传调试信息:自定义 50x 页面时,把 trace_id、上游地址、时间戳带上,运维不用翻日志就能快速定位故障节点
-
CSP 和安全头兜底:比如
Content-Security-Policy,即使接口返回 401,也要阻止恶意脚本执行,always能确保策略始终生效 -
前端统一响应解析:前端 JS 习惯读取
X-RateLimit-Remaining或X-Backend做降级/重试,错误响应里缺这个头,容易导致空指针或逻辑断裂 -
CDN 或网关链路追踪:多层代理中,每个环节都用
always注入自己的标识头,全链路 trace 才不会在某次报错时断掉
小心这些坑
add_header ... always 不会覆盖同名内置头(如 Server、Date),但会覆盖前面同名的 add_header。如果多个 location 都设置了 X-Debug,只有最后一个生效。建议:
- 把通用头(如版本、trace ID)统一写在
http或server块,加always - 业务特定头放在
location里,避免冲突 - 不要在
if块里用add_header(Nginx 官方明确不推荐),改用map+ 变量方式构造条件头 - 测试时用
curl -I http://host/path -w "\n%{http_code}\n"验证不同状态码下头是否真实存在
不复杂但容易忽略:一个 always 就能让响应头真正“始终在线”。











