Spring Boot 3.2.0全局API异常处理器未生效,Tomcat错误页处理报错,如何禁用错误页处理?
Spring Boot 3.2.0全局API异常处理器未生效,Tomcat错误页处理报错,如何禁用错误页处理?
看起来你遇到的核心问题是Spring Security过滤器链中抛出的异常没被@ControllerAdvice捕获,反而触发了Tomcat的错误页转发机制,导致出现Exception Processing ErrorPage的报错。下面我给你一步步拆解解决思路:
一、为什么全局异常处理器没生效?
你的UnauthorizedAccessException是在ApiKeyAuthFilter这个Spring Security过滤器里抛出的,而@ControllerAdvice只能处理**Controller层(DispatcherServlet之后)**抛出的异常。过滤器链的异常发生在DispatcherServlet之前,根本到不了你的全局异常处理器,反而会被Tomcat的错误页机制接管,尝试转发到/error端点,这就是你看到报错的原因。
二、解决方案步骤
1. 用Spring Security的AuthenticationEntryPoint处理过滤器层异常
我们需要让Spring Security自己接管认证异常的处理,而不是交给Tomcat。先创建一个自定义的认证入口点:
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.MediaType; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import com.fasterxml.jackson.databind.ObjectMapper; import rs.yettel.roamingbarring.exception.UnauthorizedAccessException; import rs.yettel.roamingbarring.model.ApiResponseWrapper; import rs.yettel.roamingbarring.model.ApiErrorResponse; import org.springframework.http.HttpStatus; public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { private static final String API_ID_CODE = "你的API_ID_CODE值"; private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { // 针对性处理我们自定义的UnauthorizedAccessException if (authException.getCause() instanceof UnauthorizedAccessException ex) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 构建自定义的错误响应体 ApiResponseWrapper errorResponse = new ApiResponseWrapper( new ApiErrorResponse( HttpStatus.UNAUTHORIZED.value() + "." + API_ID_CODE + "." + ex.getErrorType().getCode(), ex.getErrorType().getMessage() ) ); objectMapper.writeValue(response.getWriter(), errorResponse); } else { // 兜底处理其他认证异常 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType(MediaType.APPLICATION_JSON_VALUE); objectMapper.writeValue(response.getWriter(), new ApiResponseWrapper(new ApiErrorResponse("401.xxx.001", "未授权访问"))); } } }
然后在你的Security配置类中注册这个入口点:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; @Configuration @EnableWebSecurity public class SecurityConfig { private final ApiKeyAuthFilter apiKeyAuthFilter; public SecurityConfig(ApiKeyAuthFilter apiKeyAuthFilter) { this.apiKeyAuthFilter = apiKeyAuthFilter; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .addFilterBefore(apiKeyAuthFilter, AbstractPreAuthenticatedProcessingFilter.class) // 配置自定义认证入口点,接管过滤器层异常 .exceptionHandling(ex -> ex .authenticationEntryPoint(new CustomAuthenticationEntryPoint()) ); return http.build(); } }
2. 禁用Tomcat错误页转发机制
为了彻底避免Tomcat触发错误页处理,在Spring Boot配置文件中添加以下设置:
application.properties:
# 禁用默认的白标错误页,避免Tomcat转发到/error server.error.whitelabel.enabled=false
application.yml:
server: error: whitelabel: enabled: false
三、额外检查点
- 确认你的
ApiKeyAuthFilter中抛出的异常正确传递给了Spring Security(比如可以用throw new AuthenticationException("xxx", ex)包装你的自定义异常) - 验证
@ControllerAdvice本身是正常工作的(可以在Controller层手动抛出一个UnauthorizedAccessException测试)
这样调整后,当没有Bearer token时,就能返回你自定义的ApiResponseWrapper响应,不会再出现Tomcat的错误页处理报错了。
备注:内容来源于stack exchange,提问作者Dobrosav Vlaskovic
相关产品推荐
相关产品推荐

