Nginx 不支持 location 嵌套,add_header 不继承且会重置同名响应头;internal 跳转后原 location 头全失效;CORS 和安全头需加 always;后端缓存头需用 expires 或 hide_header 覆盖。

nginx 根本不支持 location 嵌套——所谓“多级嵌套下的 add_header”在语法上直接报错,压根不存在。真正要防的,是配置层级间隐性覆盖导致的安全头丢失、CORS 失效、错误页无防护等真实问题。
add_header 不继承,一写就丢父级头
只要某个 location 块里出现任意一条 add_header,它就自动放弃继承 server 或 http 块中所有同名响应头。这不是值被替换,而是整个头集合被重置为“仅本 location 内声明的那些”。
- server 块写了 add_header X-Content-Type-Options "nosniff";
- location /api/ 只写了 add_header Cache-Control "no-store";
- 结果:访问 /api/ 时,X-Content-Type-Options 彻底消失
想保留通用安全头?必须在每个用到 add_header 的 location 里手动重复写,或用 include 引入统一的 security-headers.conf。
internal 重定向后,原 location 的头全失效
通过 try_files、rewrite last、error_page 或 named location(如 @backend)触发 internal 跳转时,Nginx 会完全丢弃源 location 的 add_header,只看目标 location 是否显式配置。
- location / { try_files $uri @backend; }
- location @backend { internal; add_header X-Source "upstream"; }
- 最终响应只有 X-Source: upstream,主 location 里的任何头都不带
关键点:跳转终点 location 必须重新写全所需响应头,不能依赖上游配置。
OPTIONS 预检和错误响应默认不生效,always 是刚需
add_header 默认只对 2xx/3xx 响应生效。而 OPTIONS 预检成功返回 204(属 2xx),看似够用——但若没加 always,且头写在 if 块外或未统一管控,CORS 头大概率不会发出。
- CORS 相关头必须集中写在同一 location 块内
- 每条都必须带 always 参数:add_header Access-Control-Allow-Origin "$http_origin" always;
- 安全类头(如 Strict-Transport-Security、X-Frame-Options)也建议统一加 always,确保 404、500 等错误页同样受保护
后端缓存头容易“抢跑”,别只靠 add_header
如果上游(PHP、Node、proxy_pass 后端)已返回 Cache-Control,仅用 add_header 很可能生成两个同名头。浏览器通常取第一个——也就是后端的值,你的配置形同虚设。
- 推荐优先用 expires 指令:它自动设置 Expires 和 Cache-Control,并隐式覆盖后端同类头
- 或搭配 proxy_hide_header 先屏蔽再添加(proxy 场景)
- fastcgi 场景需用 fastcgi_hide_header,proxy_hide_header 对其无效










