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

Spring Boot 3.0迁移后@ControllerAdvice全局异常处理器未生效

Spring Boot 3.0迁移后自定义异常处理及认证失败响应问题解决

一、自定义GlobalExceptionHandler未生效,内置异常返回标准Problem Details

问题原因

  1. Spring Boot 3.0默认启用RFC 7807 Problem Details规范,内置的ProblemDetailsExceptionHandler会优先处理部分内置异常(如类型转换错误TypeMismatchException),导致自定义ResponseEntityExceptionHandler的逻辑未触发。
  2. 你的GlobalExceptionHandler仅实现了FileAccessException的处理,未覆盖ResponseEntityExceptionHandler中针对内置异常的处理方法(比如handleTypeMismatch),因此这类异常仍走默认流程。

解决方案

  1. 重写ResponseEntityExceptionHandler中的内置异常处理方法
    针对你遇到的类型转换错误,重写对应方法并添加自定义字段:
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private static ErrorResponse mapToErrorResponse(Exception e, ApplicationError applicationError, String errorMessage, HttpStatus status) {
        return ErrorResponse.builder(e, status, errorMessage)
                .property("code", String.valueOf(applicationError.getCode()))
                .property("timestamp", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(Instant.now()))
                .build();
    }

    @ExceptionHandler(FileAccessException.class)
    public ErrorResponse fileAccessException(FileAccessException fae) {
        log.error("File access Exception", fae);
        return mapToErrorResponse(fae, fae.getApplicationError(), fae.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    // 重写类型转换异常处理逻辑
    @Override
    protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // 自定义错误码,可根据业务场景调整
        ApplicationError error = ApplicationError.of(24, "参数类型不匹配");
        ErrorResponse errorResponse = ErrorResponse.builder(ex, status, ex.getMessage())
                .property("code", String.valueOf(error.getCode()))
                .property("timestamp", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(Instant.now()))
                .build();
        return handleExceptionInternal(ex, errorResponse, headers, status, request);
    }

    // 按需重写其他内置异常处理方法,如handleMethodArgumentNotValid、handleHttpMessageNotReadable等
}
  1. 全局配置调整(可选)
    若需完全禁用默认Problem Details自动配置(不推荐,建议通过重写方法扩展),可在启动类中排除相关配置:
@SpringBootApplication(exclude = ProblemDetailsAutoConfiguration.class)
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

二、UrlAuthenticationFailureHandler响应体为空

问题原因

Spring Security的认证失败处理独立于Spring MVC错误机制,server.error相关配置仅对MVC层面异常生效,无法控制认证失败的响应输出。默认UrlAuthenticationFailureHandler仅返回状态码,不会写入响应体。

解决方案

自定义AuthenticationFailureHandler,主动写入JSON响应:

@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());

        // 构建自定义响应体
        Map<String, Object> errorResponse = new HashMap<>();
        errorResponse.put("type", "about:blank");
        errorResponse.put("title", "Unauthorized");
        errorResponse.put("status", HttpStatus.UNAUTHORIZED.value());
        errorResponse.put("detail", exception.getMessage());
        errorResponse.put("instance", request.getRequestURI());
        errorResponse.put("timestamp", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(Instant.now()));
        errorResponse.put("code", 40101); // 自定义认证失败错误码

        new ObjectMapper().writeValue(response.getWriter(), errorResponse);
    }
}

在Spring Security配置中注入并使用该处理器:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    public SecurityConfig(CustomAuthenticationFailureHandler customAuthenticationFailureHandler) {
        this.customAuthenticationFailureHandler = customAuthenticationFailureHandler;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .formLogin(form -> form.failureHandler(customAuthenticationFailureHandler))
                .exceptionHandling(ex -> ex
                        .authenticationEntryPoint((request, response, authException) ->
                                customAuthenticationFailureHandler.onAuthenticationFailure(request, response, authException)
                        )
                );
        return http.build();
    }
}

内容的提问来源于stack exchange,提问作者César Castro Aroche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:02:33