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

Spring Boot 2.7.18全局异常处理配置(不禁用自动配置)

解决方案:Spring Boot 2.7.18 全局异常处理(兼容单页应用+REST端点)

核心结论

你的思路没问题,ResponseEntityExceptionHandler是Spring Boot实现全局异常处理的标准方式,问题出在配置冲突导致静态资源(Angular单页应用文件)无法被正确处理,同时异常处理逻辑未覆盖400、500这类容器级错误。


方案一:保留Spring Boot默认配置(推荐)

无需添加@EnableWebMvc,也不要修改spring.web.resources.add-mappings=false,通过以下调整实现全局异常处理:

1. 修正全局异常处理器代码

覆盖ResponseEntityExceptionHandler的更多默认方法,同时区分API请求和前端静态资源/页面请求,避免影响Angular应用加载:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

@ControllerAdvice
class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private static final Logger logger = Logger.getLogger(GlobalExceptionHandler.class.getName());
    private static final String GENERIC_ERROR_MSG = "……您的请求无法完成……";

    // 处理所有未被捕获的异常(含REST端点抛出的异常)
    @ExceptionHandler(Throwable.class)
    ResponseEntity<Object> handleAllUncaughtExceptions(Throwable ex, HttpServletRequest request) {
        // 记录异常详情用于排查
        logger.severe("请求路径: " + request.getRequestURI() + " 发生异常: " + ex.getMessage());
        ex.printStackTrace();

        // 区分API请求和页面请求
        if (isApiRequest(request)) {
            Map<String, String> responseBody = new HashMap<>();
            responseBody.put("message", GENERIC_ERROR_MSG);
            return new ResponseEntity<>(responseBody, HttpStatus.INTERNAL_SERVER_ERROR);
        } else {
            // 前端页面请求,返回自定义错误页或重定向到首页(按需调整)
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("error.html");
        }
    }

    // 处理400 Bad Request(如参数绑定错误)
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        HttpServletRequest nativeRequest = (HttpServletRequest) request.getNativeRequest();
        logger.severe("400错误: 请求路径=" + nativeRequest.getRequestURI() + ", 原因=" + ex.getMessage());
        
        if (isApiRequest(nativeRequest)) {
            Map<String, String> responseBody = new HashMap<>();
            responseBody.put("message", GENERIC_ERROR_MSG);
            return new ResponseEntity<>(responseBody, status);
        }
        return super.handleExceptionInternal(ex, body, headers, status, request);
    }

    // 处理404错误(仅针对API请求,前端路由由Angular处理)
    @Override
    protected ResponseEntity<Object> handleNoHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        HttpServletRequest nativeRequest = (HttpServletRequest) request.getNativeRequest();
        logger.warning("404错误: 请求路径=" + nativeRequest.getRequestURI());
        
        if (isApiRequest(nativeRequest)) {
            Map<String, String> responseBody = new HashMap<>();
            responseBody.put("message", GENERIC_ERROR_MSG);
            return new ResponseEntity<>(responseBody, HttpStatus.NOT_FOUND);
        } else {
            // 前端单页应用路由,重定向到index.html让Angular处理
            return ResponseEntity.status(HttpStatus.OK)
                    .body("index.html");
        }
    }

    // 根据实际API前缀判断是否为API请求(示例为/api/**)
    private boolean isApiRequest(HttpServletRequest request) {
        return request.getRequestURI().startsWith("/api/");
    }
}

2. 添加必要配置

在application.properties中仅添加:

# 仅对API请求抛出404异常,静态资源请求不触发
spring.mvc.throw-exception-if-no-handler-found=true

原代码未触发的原因

  • @ExceptionHandler(Throwable.class)不会捕获容器级错误(如默认的400、404处理),需覆盖ResponseEntityExceptionHandler对应方法。
  • 未区分API和前端请求,导致静态资源请求被异常处理器拦截,无法加载。

方案二:使用@EnableWebMvc并恢复Spring Boot默认配置

若必须使用@EnableWebMvc,需手动注册Spring Boot默认资源处理器,避免静态资源无法访问:

1. 创建WebMvc配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
class WebMvcConfig implements WebMvcConfigurer {

    // 恢复Spring Boot默认静态资源映射
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/", "classpath:/public/", "classpath:/resources/", "classpath:/META-INF/resources/")
                .setCachePeriod(0);
    }
}

2. 复用方案一中的异常处理器

保持方案一的GlobalExceptionHandler实现,同时添加spring.mvc.throw-exception-if-no-handler-found=true配置。


额外注意事项

  • WebSocket异常处理:WebSocket异常需单独处理,可通过@ServerEndpoint的onError方法或实现WebSocketHandlerDecoratorFactory全局处理。
  • 日志优化:建议用SLF4J/Logback替代JDK Logger,更灵活记录异常堆栈。
  • 前端路由兼容:Angular单页应用的非API 404请求需重定向到index.html,由Angular路由引擎处理页面跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:36:01