Nginx需通过proxy_set_header X-Forwarded-Proto $scheme;传递原始协议,后端再解析该头以正确识别HTTPS;同时应配置X-Forwarded-Host、X-Forwarded-Port和Host头,确保后端还原真实请求上下文。

直接在 Nginx 配置中传递正确的协议信息,就能让后端应用准确识别客户端是用 http 还是 https 访问的。关键不是后端自己猜,而是由 Nginx 明确告诉它。
为什么会出现 Scheme 判定错误?
当用户通过 HTTPS 访问 Nginx,而 Nginx 反向代理到后端 HTTP 服务(如 Tomcat 的 8080 端口)时:
- 后端调用
request.getScheme()或request.isSecure()得到的是http和false - 因为实际与后端通信的是 HTTP,Nginx 没有把“用户最初用的是 HTTPS”这个事实传过去
- 结果导致生成的跳转链接、资源路径、安全头等全部出错(比如重定向回 http:// 而非 https://)
核心配置:用 X-Forwarded-Proto 传递协议
在 Nginx 的 location 块中添加这一行:
proxy_set_header X-Forwarded-Proto $scheme;
其中 $scheme 是 Nginx 内置变量,值为 http 或 https,代表客户端与 Nginx 建立连接时使用的协议。
这行配置会把原始请求的协议作为 HTTP 请求头发送给后端,例如:X-Forwarded-Proto: https
后端必须解析这个头才能生效
仅配置 Nginx 不够,后端需启用对 X-Forwarded-Proto 的识别:
-
Spring Boot(内置 Tomcat):在
application.properties中加server.tomcat.protocol-header=x-forwarded-proto -
独立 Tomcat:在
server.xml的<host></host>内添加<valve classname="org.apache.catalina.valves.RemoteIpValve"></valve>
该 Valve 默认从X-Forwarded-Proto设置request.getScheme()和request.isSecure() -
其他框架(如 Flask/Django):需手动读取请求头
X-Forwarded-Proto,并据此判断是否为安全连接
配套建议:保持 Host 和 Port 一致性
避免因协议误判引发的连锁问题,建议同步传递 Host 和 Port:
-
proxy_set_header X-Forwarded-Host $host;—— 保留原始域名 -
proxy_set_header X-Forwarded-Port $server_port;—— 若前端端口非标准(如 8443),可辅助后端构建正确 URL -
proxy_set_header Host $http_host;—— 防止后端因 Host 头丢失而返回 400 或错误响应
这些头共同作用,能让后端重建出用户浏览器地址栏里看到的真实请求上下文。


















