如何在 Spring Boot 中统一处理 404 异常并返回 JSON 响应

通过配置 `spring.mvc.throw-exception-if-no-handler-found=true` 并调整静态资源路径,可使未匹配的请求触发 `@exceptionhandler`,从而实现 404 异常的全局 json 格式化响应。

在 Spring Boot 中,@ControllerAdvice(或其 REST 专用变体 @RestControllerAdvice)配合 @ExceptionHandler 是处理控制器层异常的标准方式。但默认情况下,404(Not Found)错误并不会进入 @ExceptionHandler 流程——因为该异常发生在 DispatcherServlet 的请求分发阶段(即“找不到任何 HandlerMapping 匹配该 URL”),而非控制器执行过程中抛出的异常。此时 Spring Boot 会直接返回 Whitelabel 错误页(HTML),而非调用你的全局异常处理器。

要让 404 也能被 @ExceptionHandler 捕获,关键在于 强制 Spring 在无处理器匹配时抛出 NoHandlerFoundException,而非静默返回 404 响应。这需要两个协同配置:

✅ 步骤一:启用异常抛出机制

在 application.yml(或 application.properties)中启用:

spring:
  mvc:
    throw-exception-if-no-handler-found: true

⚠️ 注意:仅设置此项不够!Spring Boot 默认将静态资源路径设为 /**,而 Whitelabel 错误页本质上是静态资源(由 BasicErrorController 提供)。若不调整静态路径,throw-exception-if-no-handler-found 将被忽略(因为 /error 路径仍能被静态资源处理器匹配)。

✅ 步骤二:隔离静态资源路径

方案 A(推荐):显式限定静态资源路径,避免覆盖 /error:

spring:
  mvc:
    throw-exception-if-no-handler-found: true
    static-path-pattern: /static/**

这样,所有非 /static/** 开头的请求(如 /api/v1/itemss)若无对应 Controller,则触发 NoHandlerFoundException。

方案 B:禁用自动配置,手动接管 Web MVC(适用于需深度定制场景):

@Configuration
@EnableWebMvc // ⚠️ 关闭 Spring Boot 的 WebMvcAutoConfiguration
public class WebConfig implements WebMvcConfigurer {
    // 可选:自定义资源处理器等
}

再配合 spring.mvc.throw-exception-if-no-handler-found=true 即可生效。

✅ 步骤三:添加 404 异常处理器

在你的 @RestControllerAdvice 类中添加:

@ExceptionHandler(NoHandlerFoundException::class)
fun handleNoHandlerFound(
    exception: NoHandlerFoundException,
    request: HttpServletRequest
): ResponseEntity {
    logger().warn("404 Not Found: {}", exception.requestURL)
    val notF

ound = HttpStatus.NOT_FOUND val apiError = ApiError( requestURI = exception.requestURL, status = notFound.value(), statusText = notFound.reasonPhrase, createdAt = OffsetDateTime.now(), errorMessage = "Requested resource does not exist" ) return ResponseEntity(apiError, notFound) }
? 提示:NoHandlerFoundException 的 requestURL 字段需通过 exception.requestURL 获取(Kotlin 中注意空安全),或从 request.requestURL.toString() 提取。

✅ 最终效果

访问 GET /api/v1/itemss 将返回标准 JSON:

{
  "requestUri": "/api/v1/itemss",
  "status": 404,
  "statusText": "Not Found",
  "createdAt": "2025-01-12T16:52:06.932108+02:00",
  "errorMessage": "Requested resource does not exist"
}

⚠️ 注意事项

  • 确保 NoHandlerFoundException 的包导入正确:org.springframework.web.servlet.NoHandlerFoundException;
  • 若使用 Spring Security,请确认 /error 路径未被拦截(通常需放行);
  • @EnableWebMvc 会完全关闭 Spring Boot 的 Web 自动配置,仅在必要时选用;
  • 生产环境建议结合 ErrorAttributes 或 ErrorController 做更健壮的错误溯源。

通过以上三步配置,即可将 404 纳入统一的 JSON 异常处理体系,保持 API 响应风格一致,提升客户端集成体验与服务可观测性。