惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
D
Docker
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
Jina AI
Jina AI
小众软件
小众软件
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
美团技术团队
爱范儿
爱范儿
V
V2EX
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
博客园 - 司徒正美
博客园 - 叶小钗
S
SegmentFault 最新的问题
量子位
S
Secure Thoughts
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
O
OpenAI News
L
LINUX DO - 最新话题
罗磊的独立博客
SecWiki News
SecWiki News
雷峰网
雷峰网
Recent Announcements
Recent Announcements
V2EX - 技术
V2EX - 技术
T
Tailwind CSS Blog
H
Hacker News: Front Page
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
云风的 BLOG
云风的 BLOG
Schneier on Security
Schneier on Security
T
The Blog of Author Tim Ferriss
IT之家
IT之家
博客园 - 聂微东
腾讯CDC
N
News | PayPal Newsroom
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
aimingoo的专栏
aimingoo的专栏
Webroot Blog
Webroot Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
K
Kaspersky official blog

码志

如何在 IT 运维中节省开支 借助 Let's Encrypt 节省 SSL 证书费用 清除 GitHub 上的幽灵通知 Java|FreeMarker 复用 layout DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI Mac mini 外接三方键盘如何微调音量 Java|小数据量场景的模糊搜索体验优化 家里老人迷信医疗广告?我可能找到办法了 iOS|解决 setBrightness 调节屏幕亮度不生效的问题
解决访问 https 网站时,后端重定向或获取 URL 变成 http 的问题
Zhuang Ma · 2025-11-14 · via 码志

一种常见的服务部署架构是 Nginx 反向代理后端 Java 应用服务器,Nginx 监听 443 端口处理 https 请求,然后转发给后端服务器。

对应的 Nginx 配置大致如下:

upstream www {
    server 192.168.1.101:8080  weight=100 max_fails=3 fail_timeout=10s;
    server 192.168.1.102:8080  weight=100 max_fails=3 fail_timeout=10s;
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://www;
    }
}

即:客户端与 Nginx 之间是 https,Nginx 与后端 Java 应用服务器之间是 http。

这样可能会遇到一些问题,如:

  1. HttpServletRequest.getRequestURL() 获取到的 URL 是 Nginx 与后端服务器之间的 http URL,比如 http://192.168.1.101:8080/xxx
  2. HttpServletResponse.sendRedirect() 生成的重定向 URL 也是 http URL。

要解决这些问题,可以通过 Nginx 配置 + 少量后端代码修改来实现。

解决应用中获取到的 URL 的问题

用户实际访问的是 https://example.com/xxx,但是后端应用获取到的 URL 是 http://192.168.1.101:8080/xxx,如何让后端应用获取到正确的 URL 呢?

第一步,Nginx 可以通过 proxy_set_header Host 指令将客户端请求的 Host 头传递给后端服务器:

location / {
    # ...
    proxy_set_header Host $host;
}

这样,后端应用通过 HttpServletRequest.getRequestURL() 获取到的 URL 就是 http://example.com/xxx 了。

但此时,协议仍然不对,还是 http。

要给后端应用传递正确的协议,通常的做法是使用 X-Forwarded-Proto 头:

location / {
    # ...
    proxy_set_header X-Forwarded-Proto $scheme;
}

添加这个头之后并不会让 HttpServletRequest.getRequestURL() 直接返回 https URL,需要在后端应用中做一些处理。以 Java 应用为例,可以通过一个过滤器(Filter)来修改 request 的 scheme:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class XForwardedProtoFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            String xForwardedProto = httpRequest.getHeader("X-Forwarded-Proto");
            if (StringUtils.isNotBlank(xForwardedProto) && !xForwardedProto.equalsIgnoreCase(httpRequest.getScheme()) && xForwardedProto.equalsIgnoreCase("https")) {
                httpRequest = new HttpServletRequestWrapper(httpRequest) {
                    @Override
                    public String getScheme() {
                        return xForwardedProto;
                    }

                    @Override
                    public StringBuffer getRequestURL() {
                        StringBuffer requestURL = super.getRequestURL();
                        if (requestURL != null && requestURL.length() > 0) {
                            int index = requestURL.indexOf("://");
                            if (index > 0) {
                                requestURL.replace(0, index, xForwardedProto);
                            }
                        }
                        return requestURL;
                    }
                    
                };
            }
            chain.doFilter(httpRequest, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

至此,后端应用通过 HttpServletRequest.getRequestURL() 获取到的 URL 就是 https://example.com/xxx 了。

解决重定向 URL 的问题

后端应用通过 HttpServletResponse.sendRedirect() 生成的重定向 URL 也是 http URL,如何让它变成 https 呢?

这个问题可以通过 Nginx 的另一指令 proxy_redirect 来解决,该指令用于修改从后端服务器返回的 LocationRefresh 响应头。

location / {
    # ...
    proxy_redirect http:// $scheme://;
}

这样,当后端应用返回一个重定向响应时,Nginx 会将 Location 头中的 http:// 替换为 $scheme://,即 https://

进一步思考:当 Nginx 前面还有负载均衡器时

在很多情况下,Nginx 前面可能还有商用负载均衡器(如 AWS ELB、阿里云 SLB 等),这时需要考虑负载均衡器与 Nginx 之间的协议问题。

如果负载均衡器与 Nginx 之间是 http,而 Nginx 与后端应用之间是 http,那么就需要在负载均衡器和 Nginx 之间添加 X-Forwarded-Proto 头,以便 Nginx 能够正确地识别原始请求的协议。

主流的负载均衡器配置项里应该都有添加 X-Forwarded-Proto 头的选项开关,比如阿里云:

需要注意的是这样配置后,Nginx 配置也需要做相应的调整,将 $scheme 替换为 $http_x_forwarded_proto: (此种场景 $scheme 为负载均衡器与 Nginx 之间的协议 http,$http_x_forwarded_proto 为负载均衡器通过 Header 透传过来的前端访问协议 https。)

location / {
    # ...
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_redirect http:// $http_x_forwarded_proto://;
}

参考链接

文档信息