HSTS响应头丢失主因是add_header不继承且被内层location覆盖,需在所有location中显式声明或用always参数确保发送;请求头丢失则因proxy_set_header未透传或underscores_in_headers未开启。

排查 HSTS 与多级反向代理(如 Nginx → Tomcat)中的头丢失问题,关键在于区分两类不同性质的头部:一类是服务端**响应头**(如 Strict-Transport-Security),另一类是客户端**请求头**(如 X-User-Token、X-Forwarded-Proto)。它们丢失的机制、位置和修复方式完全不同,不能混为一谈。
先确认是哪类头丢了
打开浏览器开发者工具或运行 curl -I https://your-domain.com,观察响应头中是否含 Strict-Transport-Security:
- 若完全没出现 → 属于服务端响应头未发出,问题在 Nginx 的
add_header配置逻辑(如嵌套覆盖、未加always) - 若出现了,但 Tomcat 日志或代码里收不到
X-Forwarded-Proto或自定义头(如X-Request-ID)→ 属于客户端请求头未透传,问题在 Nginx 的proxy_set_header配置链路
查 HSTS 响应头为什么没发出来
HSTS 头不出现,90% 是因为 add_header 在多层 location 中被覆盖或遗漏:
-
add_header不继承,只取当前生效块中最后一条;server 块写了,但location ~ \.jsp$或location /api里没写,该路径下 HSTS 就会消失 - 必须对所有可能返回内容的
location(包括静态资源、JSP、API 接口)显式声明,或统一改用带always参数的写法:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - 验证不能只测首页;要分别测:
curl -I https://d.com/、curl -I https://d.com/app.jsp、curl -I https://d.com/favicon.ico,任一缺失即说明对应 location 未配置
查请求头(如 X-Forwarded-Proto、X-User-Token)为什么到不了 Tomcat
Tomcat 收不到头,根本原因不是“Nginx 没转发”,而是它默认不自动透传非标准头,且对含下划线字段更敏感:
- 确保最外层 Nginx 的
http{}块启用:underscores_in_headers on;(必须全局开启,否则X_User_ID这类头直接被静默丢弃) - 每一级代理(包括中间 Nginx 和最终到 Tomcat 的那层)都要在
location中显式透传:proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;proxy_set_header X-User-Token $http_x_user_token; - Tomcat 需信任 Nginx 的转发:在
server.xml的Connector中添加:remoteIpHeader="x-forwarded-for" protocolHeader="x-forwarded-proto" remoteIpProxies="192.168.0.0/16,10.0.0.0/8"(填你 Nginx 实际 IP 段)
快速定位丢在哪一级
用日志和变量分段验证,比盲改配置高效得多:
- 在 Nginx access_log 中加入
$http_x_forwarded_proto和$http_x_user_token,确认第一层是否收到原始头 - 在 Tomcat 的
logging.properties中开启 access log,并打印所有 header,看是空、null 还是值异常 - 若 Nginx 日志有值、Tomcat 没收到 → 问题在 proxy_set_header 配置或 Tomcat 信任配置;
若 Nginx 日志也为空 → 检查客户端是否真发了,或上游 CDN/负载均衡是否剥离了头


















