doFilter多次调用问题:如何控制行为或解决重定向结果异常?
问题解决思路
核心问题是同一请求多次触发doFilter执行,导致logout标志被置为false后,后续执行读取到错误值。由于无法继承OncePerRequestFilter,我们可以手动实现"一次请求仅处理一次"的逻辑,通过给HttpServletRequest添加标记属性避免重复执行重定向逻辑。
具体修改方案
1. 在doFilter方法中添加请求处理标记检查
进入核心逻辑前,先判断当前请求是否已经处理过重定向,避免重复执行:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 检查请求是否已处理过重定向 if (httpRequest.getAttribute("REDIRECT_HANDLED") != null) { chain.doFilter(request, response); return; } if (authentication == null) { if (SomeCondition) { doSomethingA(); } else { doSomethingB(httpRequest, (HttpServletResponse) response); return; } } chain.doFilter(request, response); }
2. 调整doSomethingB方法,添加标记并优化logout标志处理
执行重定向前给请求设置已处理标记,同时确保logout标志的修改不会影响同一请求的后续执行:
void doSomethingB(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException { // 设置请求已处理标记,避免同一请求重复执行 httpRequest.setAttribute("REDIRECT_HANDLED", Boolean.TRUE); httpResponse.setStatus(302); boolean logout = Boolean.valueOf(String.valueOf(httpRequest.getSession().getAttribute(LOGOUT))); String redirectUrl = getRedirectUrl(logout); // 清除session中的logout标志,避免影响后续请求 httpRequest.getSession().setAttribute(LOGOUT, false); httpResponse.sendRedirect(redirectUrl); }
3. 可选优化:用请求属性替代session存储logout标志
如果logout仅针对当前请求生效,完全可以不用session,改用HttpServletRequest的属性,避免session污染:
// Controller中修改为设置请求属性 @RequestMapping(value = "/logout", method = RequestMethod.GET, produces = { MediaType.TEXT_HTML_VALUE }) public String logout(HttpServletRequest request, HttpServletResponse response, Model model) throws UnsupportedEncodingException { request.setAttribute(LOGOUT, true); // 用请求属性替代session return logoutUrl; } // doSomethingB中读取请求属性 boolean logout = Boolean.TRUE.equals(request.getAttribute(LOGOUT));
原理说明
Servlet容器中,Filter可能因为请求转发、include操作或框架内部逻辑被多次调用。通过给HttpServletRequest添加专属标记,我们可以确保核心重定向逻辑在一次请求生命周期内仅执行一次,完全模拟OncePerRequestFilter的核心行为,同时不需要继承该类。
内容的提问来源于stack exchange,提问作者Techie
相关产品推荐
相关产品推荐

