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

JSF会话超时重定向时如何避免javax.servlet.ServletException异常

问题根因

你当前的写法只通知了JSF无需执行后续的渲染响应阶段,但没有终止当前执行栈的代码逻辑,会话超时后未完成初始化的Bean属性被页面EL表达式解析时就会触发空指针异常,错误日志也随之生成。

解决方案

按优先级从高到低提供3种可行方案:

方案1:全局过滤器实现会话超时校验(最推荐)

直接在Servlet层做超时拦截,根本不会进入JSF生命周期,从根源避免后续EL渲染的问题,适合全局统一的会话超时控制:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", asyncSupported = true)
public class SessionTimeoutFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        String contextPath = req.getContextPath();

        // 放行公共资源、登录页等无需校验的路径
        String requestUri = req.getRequestURI();
        if (requestUri.startsWith(contextPath + "/login") || requestUri.startsWith(contextPath + "/public/")) {
            chain.doFilter(request, response);
            return;
        }

        // 会话校验逻辑
        HttpSession session = req.getSession(false);
        if (session == null || session.getAttribute("loginUser") == null) {
            resp.sendRedirect(contextPath + "/login.xhtml?timeout=1");
            return;
        }

        chain.doFilter(request, response);
    }
}

方案2:修正Backing Bean内的重定向写法

如果必须在Backing Bean内做超时判断,使用JSF原生的重定向API,执行后立刻终止当前方法执行:

import javax.faces.context.FacesContext;
import javax.faces.application.ResponseCompleteException;

// 会话超时判断逻辑
if (sessionExpired) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    String redirectUrl = facesContext.getExternalContext().getRequestContextPath() + "/login.xhtml";
    // 原生redirect方法会自动设置302状态、Location头,自动调用responseComplete
    facesContext.getExternalContext().redirect(redirectUrl);
    // 无返回值的方法(比如@PostConstruct)直接抛ResponseCompleteException终止流程
    throw new ResponseCompleteException();
    // 有返回值的动作方法直接return null即可,无需抛异常
    // return null;
}

如果你的项目使用PrimeFaces,可使用同时兼容普通请求和Ajax请求的写法:

import org.primefaces.context.RequestContext;

if (sessionExpired) {
    RequestContext.getCurrentInstance().redirect(redirectURL);
    throw new ResponseCompleteException();
}

方案3:临时规避错误日志

如果暂时无法调整业务逻辑,可以在日志配置中过滤掉该类会话超时触发的NPE,避免无效告警。但该方案只是临时规避,优先选择前两种方案从根源解决问题。


内容的提问来源于stack exchange,提问作者John Hammond

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:36:07