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

Spring Boot 3.3.2中ServletException无法被/error控制器捕获的问题

问题分析

自定义的AbstractPreAuthenticatedProcessingFilter属于Servlet级别过滤器,执行顺序在Spring MVC的DispatcherServlet之前。当它抛出ServletException时,请求还未进入Spring MVC的处理流程,因此@ControllerAdvice、HandlerExceptionResolver等Spring异常处理机制无法接管,最终由Tomcat的默认错误处理器返回堆栈信息,而非自定义的/error页面。

解决方案

以下是三种可行的解决方式,可根据项目实际情况选择:

1. 在自定义过滤器内手动调用Spring异常处理器

让过滤器通过Spring的HandlerExceptionResolver处理异常,再渲染视图或转发到/error端点:

@Component
public class CustomPreAuthFilter extends AbstractPreAuthenticatedProcessingFilter {

    @Autowired
    private HandlerExceptionResolver handlerExceptionResolver;

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        String token = request.getHeader("X-Auth-Token");
        if (token == null || !token.equals("valid-token")) {
            ServletException exception = new ServletException("无效或缺失认证令牌");
            try {
                // 调用Spring异常处理器获取视图
                ModelAndView mav = handlerExceptionResolver.resolveException(
                        request, getResponse(), null, exception
                );
                if (mav != null) {
                    // 渲染视图,完成响应处理
                    mav.getView().render(mav.getModelMap(), request, getResponse());
                    return null; // 返回null表示已处理异常,终止后续流程
                }
            } catch (Exception e) {
                // 处理渲染异常
                logger.error("处理认证异常失败", e);
            }
            // 若处理器未处理,再抛出异常
            throw exception;
        }
        return token;
    }
}

2. 用全局Servlet Filter捕获前置过滤器异常

注册一个优先级较低的全局Filter,捕获所有前置Filter抛出的异常并转发到/error:

@Component
@Order(Ordered.LOWEST_PRECEDENCE - 10) // 确保在自定义PreAuthFilter之后执行
public class FilterExceptionHandler extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 转发到Spring的error端点,交由Spring处理
            ((HttpServletRequest) request).getRequestDispatcher("/error").forward(request, response);
        }
    }
}

3. 结合Spring Security的异常处理机制(若使用Spring Security)

如果项目依赖Spring Security,可通过配置AuthenticationEntryPoint来处理认证失败的异常,直接转发到自定义错误页面:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, CustomPreAuthFilter preAuthFilter) throws Exception {
    http
        .addFilterBefore(preAuthFilter, UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling(config -> 
            config.authenticationEntryPoint((request, response, authException) -> {
                // 转发到自定义error页面
                request.getRequestDispatcher("/error").forward(request, response);
            })
        );
    return http.build();
}

注意:此时建议在过滤器中抛出Spring Security的AuthenticationException子类(如BadCredentialsException),而非ServletException,以便Security的异常处理机制识别。

额外注意事项
  • 确保自定义的/error页面能被Spring Boot识别:可放在src/main/resources/templates/error.html(模板引擎场景)或src/main/resources/static/error.html(静态资源场景),也可通过实现ErrorController自定义错误逻辑。
  • 自定义过滤器需被Spring上下文管理:通过@Component或@Bean注解注册,确保能注入Spring的Bean(如HandlerExceptionResolver)。

内容的提问来源于stack exchange,提问作者Steve Maring

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:28:31