必须添加always参数,否则Nginx仅在200、301、304、307、308等少数状态码下注入add_header,而302及多数4xx/5xx响应(如401、403、500、502)均被排除,导致Strict-Transport-Security、CORS等关键安全头缺失,引发HSTS失效、跨域拦截或XSS风险。

直接加 always 是最可靠的方式。Nginx 默认只在部分状态码(如 200、301、304、307、308)下注入 add_header,而 302 和绝大多数 5xx(如 401、403、500、502)都不在默认列表中——不加 always,这些响应里就完全不会出现你配置的安全头。
为什么必须用 always 参数
Nginx 的 add_header 指令有隐式状态码过滤机制。即使你在 server 块里统一写了安全头,只要响应是 302 或 500,这些头就会被跳过。这不是配置遗漏,而是 Nginx 的设计行为。加上 always 后,它会无视状态码,强制把头字段加到所有响应中,包括重定向和错误响应。
- 302 响应缺失
Strict-Transport-Security→ 浏览器不会启用 HSTS,后续请求可能走明文 HTTP - 302 响应缺失
Access-Control-Allow-Origin→ 前端跨域请求被拦截(尤其在重定向链中) - 500 响应缺失
X-Content-Type-Options: nosniff→ 浏览器可能 MIME 类型猜测,触发 XSS 风险
正确写法:always 必须紧贴 add_header 且位置精准
不能只在 server 块写一次就指望全局生效——add_header 不继承,子 location 必须单独声明。尤其是涉及重定向的 location,必须显式带上 always。
- ✅ 正确:
location /api/ { add_header X-Frame-Options DENY always; return 302 https://new.example.com/; } - ❌ 错误:
server { add_header X-Frame-Options DENY; } location /api/ { return 302 ...; }→ 302 响应无该头 - ⚠️ 注意:同名头多次出现时,只有最后一个生效。避免在一个 location 内重复写
add_header Access-Control-Allow-Origin
代理场景下后端返回的 302 怎么办
如果 302 是后端应用(如 Spring Boot、Node.js)直接返回的,Nginx 默认只是透传,不会自动补安全头——哪怕你配了 add_header ... always,也得确保这个指令落在能覆盖该 location 的作用域内。
- 检查是否在处理该路径的
location块中配置了带always的add_header - 若用
proxy_pass,Nginx 不会覆盖后端已有的同名响应头,但会追加自己配置的(前提是用了always) - 后端若已设
Access-Control-Allow-Origin,Nginx 新增的不会冲突;但若后端没设,就全靠 Nginx 这一层兜底
常用安全头建议都加 always
以下头字段在 302、4xx、5xx 下同样关键,推荐统一加 always:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;add_header X-Content-Type-Options nosniff always;add_header X-Frame-Options DENY always;add_header Referrer-Policy no-referrer-when-downgrade always;-
add_header Access-Control-Allow-Origin "$http_origin" always;(需配合Access-Control-Allow-Credentials "true" always;)

















