Java应用在Nginx反向代理后需透传X-Forwarded-Proto等头并用Filter修正request.getScheme()为https,才能使getRequestURL()、sendRedirect()生成正确的HTTPS链接,避免暴露内网端口或降级HTTP。

后端Java应用在Nginx反向代理后“感知不到HTTPS”,本质是原始协议信息未透传,导致request.getScheme()返回http、request.getRequestURL()拼出HTTP地址、sendRedirect()生成的跳转链接也带http://,最终暴露内网端口(如:8080)或降级到HTTP,构成安全与可用性风险。
确保Nginx正确透传协议和主机头
这是修复的前提。仅靠proxy_pass http://backend不够,必须显式设置关键Header:
-
proxy_set_header Host $host;:让后端request.getHeader("Host")拿到真实域名(如api.example.com),而非127.0.0.1:8080 -
proxy_set_header X-Forwarded-Proto $scheme;:把客户端实际使用的协议(https或http)以标准头传递 -
proxy_set_header X-Forwarded-Port $server_port;:尤其当Nginx监听非443端口(如777)时,避免后端误判端口
注意:$scheme在HTTPS请求中值为https,该值必须原样传给后端,不可硬编码。
用Filter包装Request修正协议与端口
Nginx传来的X-Forwarded-Proto不会自动改变HttpServletRequest的内部状态。需在Java层拦截并覆盖:
立即学习“Java免费学习笔记(深入)”;
- 编写一个
Filter,检查X-Forwarded-Proto是否为https且当前getScheme()不是https - 若匹配,用
HttpServletRequestWrapper重写getScheme()返回"https"、getServerPort()返回443(或根据X-Forwarded-Port动态取值) - 该Filter必须在所有业务逻辑之前执行,建议注册为
@Order(Ordered.HIGHEST_PRECEDENCE)
这样,后续调用request.getRequestURL()、response.encodeRedirectURL()等方法时,底层会基于修正后的协议和端口构造URL。
禁用不安全的重定向拼接方式
避免在代码中手动拼接跳转URL,例如:
return "redirect:http://" + request.getServerName() + ":8080/login"; // ❌ 危险!硬编码HTTP+私有端口
应统一使用Spring的重定向机制,并依赖已修正的Request上下文:
-
return "redirect:/login";→ Spring会调用response.encodeRedirectURL("/login"),自动补全协议、域名、上下文路径 - 如需外部URL,用
response.sendRedirect(absoluteUrl)前,先校验absoluteUrl是否属于白名单域名(防开放重定向漏洞)
验证是否生效
部署后,通过日志或调试确认以下三点:
- 后端收到请求时,
request.getHeader("X-Forwarded-Proto")值为"https" -
request.getScheme()返回"https"(非"http") -
response.sendRedirect("/success")实际响应头中的Location为https://example.com/success,而非http://127.0.0.1:8080/success
可临时加一行日志:log.info("Scheme: {}, URL: {}", request.getScheme(), request.getRequestURL());


















