You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:07:51