随笔 - 19  文章 - 0  评论 - 4  阅读 - 46530

解决Nginx 反代 Tomcat/Springboot 出现的ContextPath, RequestURI, getScheme, ServerPort不对的问题

问题示例

从/amp 反代到 /crm

 

请求地址:
 
打印信息(重复斜杠解决首页问题的, 略)

 

 

 

能看到contextPath是tomcat自己的/crm 而不是浏览器请求的/amp
这样就有可能导致模板引擎(JSP, Thymeleaf之类)请求头拼接错误而导致的404
也有可能导致后台进行Redirect的时候404

 

解决方案

继承HttpServletRequestWrapper类, 重写getContextPath, getRequestURI, getRequestURL, getScheme, getServerPort后两个解决nginx反代https时候的问题

nginx 配置

复制代码
       location /amp {
            proxy_pass  http://127.0.0.1:8081/crm/;
            proxy_set_header   Host             $host;
            proxy_set_header   Port             $server_port; # 配合java代码
            proxy_set_header   Request-URI      $request_uri; # 配合java代码
            proxy_set_header   Context-Path     /amp; # 配合java代码
            proxy_cookie_path  /crm             /amp;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme; # 配合java代码
        }
复制代码

HttpServletRequestWrapper

复制代码
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 对nginx转发后的contextPath进行匹配修复
 * @author xudaz
 */
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public class ParameterRequestWrapper extends HttpServletRequestWrapper {

    private final String oldContextPath;
    private final String oldRequestURI;

     ParameterRequestWrapper(HttpServletRequest request) {
         super(request);

         oldContextPath = request.getContextPath();
         oldRequestURI = request.getRequestURI();
    }

    @Override
    public String getContextPath() {
        String unknown = "unknown";
        //先从nginx自定义配置获取
        String contextPath = super.getContextPath();
        String temp = getHeader("Context-Path");
        if (temp != null && temp.length() > 0 && ! unknown.equalsIgnoreCase(temp)) {
            contextPath = temp;
        }
        return contextPath;
    }

    @Override
    public String getRequestURI() {
         // 把requestURI 的 oldContextPath 部分替换成 新的 contextPath
        String requestURI = super.getRequestURI();
        if ( requestURI.startsWith(oldContextPath) ) {
            requestURI = getContextPath() + requestURI.substring(oldContextPath.length());
        }
        return requestURI;
    }

    @Override
    public StringBuffer getRequestURL() {
        // 把 RequestURL 的 oldRequestURI 部分替换成 新的 oldRequestURI
        StringBuffer requestURL = super.getRequestURL();
        String toString = requestURL.toString();
        if ( toString.endsWith(oldRequestURI) ) {
            requestURL.replace(
                    toString.indexOf(oldRequestURI), toString.indexOf(oldRequestURI) + oldRequestURI.length()
                    , getRequestURI());
        }
        return requestURL;
    }

    @Override
    public String getScheme() {
        String unknown = "unknown";
        //先从nginx自定义配置获取
        String scheme = super.getScheme();
        String temp = getHeader("X-Forwarded-Proto");
        if (temp != null && temp.length() > 0 && ! unknown.equalsIgnoreCase(temp)) {
            scheme = temp;
        }
        return scheme;
    }

    @Override
    public int getServerPort() {
        String unknown = "unknown";
        //先从nginx自定义配置获取
        int serverPort = super.getServerPort();
        String temp = getHeader("Port");
        if (temp != null && temp.length() > 0 && ! unknown.equalsIgnoreCase(temp)) {
            serverPort = Integer.parseInt(temp);
        }
        return serverPort;
    }

}
复制代码

还没完 这是新的request, 还得用上 写个过滤器 对request对象进行替换

复制代码
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 替换适配nginx反代的request对象的过滤器
 * @author xudaz
 */
@Component
public class ParamsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ParameterRequestWrapper paramsRequest = new ParameterRequestWrapper(  (HttpServletRequest) request);
        chain.doFilter(paramsRequest, response);
    }

    @Override
    public void init(FilterConfig arg0)   {
    }

    @Override
    public void destroy() {
    }
}
复制代码

欧克 效果↓

 

 

 

posted on   尹镇镇  阅读(1052)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示