add_header是Nginx中唯一原生、官方支持的响应头添加方式,必须显式写在location等作用域内,不继承父级同名头,仅对2xx/3xx默认生效,加always参数才覆盖所有状态码。

不能在 location 块里直接用 location 指令添加响应头——它只管路由,不负责发头。真正起作用的是 add_header 指令,必须写在 location 块内部,且要注意继承规则和状态码限制。
add_header 是唯一推荐的原生方式
这是 Nginx 官方支持、无需额外模块的设置方法。语法简单:add_header 名称 值 [always];。名称和值区分大小写,值中可嵌入变量(如 $request_id),但变量为空时该头不会发出。
- 不加
always:只对 2xx、3xx(部分)、4xx(部分)等特定成功/重定向状态生效,比如return 200或proxy_pass正常响应会带,但return 301默认不带 - 加上
always:无论状态码是 200、404 还是 302,头都会发出,适合标记废弃路径或统一追踪 - 同一 location 中多个
add_header指令会全部生效,顺序不影响最终响应头顺序
同名头不继承,需显式重复
如果 server 块已设 add_header X-Frame-Options "DENY",而在某个 location /api/ 中写了 add_header X-Content-Type-Options "nosniff",那么这个 location 的响应里就只有后者——前者被完全屏蔽,不会合并也不会继承。
- 想保留父级头又要加新头?必须在该 location 中把所有需要的头都重新写一遍
- 常见组合如安全头(
X-XSS-Protection、X-Content-Type-Options、Strict-Transport-Security)建议集中管理,避免遗漏 - 不要依赖“没写就自动继承”,Nginx 的设计逻辑是“有定义即覆盖”
配合 map 实现动态值与条件控制
静态值不够用时,可用 map 在 http 块中预先定义变量映射,再在 location 中引用。比如按域名或路径设置不同服务标识:
map $host $service_name { default "web"; api.example.com "api"; assets.example.com "cdn"; }- 然后在 location 中写
add_header X-Service $service_name; -
map必须放在http块顶层,不能嵌套在server或location内 - 匹配支持正则(如
~^.*\.staging\.com$),但不支持通配符*直接写
别踩这些常见坑
看似简单,实际配置中高频出错:
- 用
rewrite ... redirect触发 302 却忘了加always,导致跳转响应里没有自定义头 - 在
location ~ \.php$里加了add_header,但 PHP 脚本自己输出了header(),结果 Nginx 的头被 PHP 覆盖(PHP 输出优先级更高) - 误把
proxy_set_header当成响应头指令——它只改发给后端的请求头,不影响返回给客户端的响应头 - 想隐藏
X-Powered-By却在 location 里写add_header X-Powered-By "",这无效;正确做法是fastcgi_hide_header X-Powered-By(针对 PHP-FPM)


















