Spring自定义Filter改写URI遇404问题求助(同Tomcat多Web应用)
问题分析与解决方案
首先看你代码里的几个明显问题:
- 语法错误:
CustomServletRequest类定义里多了一个右括号,正确写法是final class CustomServletRequest extends HttpServletRequestWrapper - 重复变量定义:
doFilterInternal方法里重复声明了String reqURI,这会导致编译错误,需删除第二个重复定义。
但核心导致404的原因是:你的Filter运行在/app这个Web应用的上下文内,仅仅修改Request的URI无法让Tomcat将请求路由到/abc应用。每个Web应用在Tomcat中是独立上下文,Filter只能在自身上下文范围内处理请求,修改URI后,Tomcat还是会在/app上下文里查找/abc/users对应的资源,自然找不到,返回404。
正确实现方式
要在同一Tomcat下跨Web应用转发请求,需使用Tomcat的跨上下文转发功能,步骤如下:
1. 配置Tomcat允许跨上下文访问
在Tomcat的conf/context.xml中添加crossContext="true"(也可在每个应用的META-INF/context.xml中单独配置):
<Context crossContext="true"> <!-- 其他原有配置 --> </Context>
2. 修改Filter代码,使用跨上下文转发
不需要自定义HttpServletRequestWrapper,直接获取/abc应用的上下文并转发请求:
@Component public class MyFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String reqURI = request.getRequestURI(); if (reqURI.startsWith("/app")) { // 构造目标路径:去掉/app前缀,拼接/abc String targetPath = "/abc" + reqURI.substring(4); // 获取/abc应用的ServletContext ServletContext abcContext = request.getServletContext().getContext("/abc"); if (abcContext != null) { // 转发请求到/abc应用的对应路径 abcContext.getRequestDispatcher(targetPath).forward(request, response); return; // 转发后不再执行原Filter链 } // 如果获取不到/abc上下文,可根据需求处理,比如返回错误或继续原请求 } // 不匹配的请求走原Filter链 filterChain.doFilter(request, response); } }
原理说明
通过request.getServletContext().getContext("/abc")可获取同一Tomcat下/abc应用的上下文,调用该上下文的getRequestDispatcher转发请求后,Tomcat会将请求路由到/abc应用中处理,同时客户端不会感知到URI变化,符合你不使用重定向的需求。
内容的提问来源于stack exchange,提问作者azure_geek
相关产品推荐
相关产品推荐

