bigywater.tech
Spring · 159

Spring MVC 的 400、404、405、406、415 各由谁抛出

遇到 400、404、405、406、415,到底是谁抛的?是 Spring MVC 的哪个组件?@ControllerAdvice 能不能接到?这篇用一个注册在最前面的异常解析器记录异常类和抛出位置,把常见的 4xx 逐个复现。

NoResourceFoundException
没有映射的路径、结尾斜杠、不存在的静态资源三种 404 的异常类,都由 ResourceHttpRequestHandler 抛出
handleNoMatch
405、406、415 三种状态码的抛出处都是 RequestMappingInfoHandlerMapping.handleNoMatch
500
要 multipart 文件却发了普通表单,得到的是 500 与 MultipartException,不是 400

404

实测 · 本机执行输出
  没有任何映射的路径:GET /nope → 404 Not Found;org.springframework.web.servlet.resource.NoResourceFoundException ← ResourceHttpRequestHandler.handleRequest
  映射是 /only-get,请求多了结尾斜杠:GET /only-get/ → 404 Not Found;org.springframework.web.servlet.resource.NoResourceFoundException ← ResourceHttpRequestHandler.handleRequest
  不存在的静态资源:GET /x.png → 404 Not Found;org.springframework.web.servlet.resource.NoResourceFoundException ← ResourceHttpRequestHandler.handleRequest
  Controller 里抛 ResponseStatusException(NOT_FOUND):GET /rse → 404 Not Found;org.springframework.web.server.ResponseStatusException ← Main.rse

404 多数来自静态资源处理器;Controller 也可能主动抛。

405 406 415

实测 · 本机执行输出
  只映射了 GET 的路径用 POST:POST /only-get → 405 Method Not Allowed;org.springframework.web.HttpRequestMethodNotSupportedException ← RequestMappingInfoHandlerMapping.handleNoMatch  Allow=GET
  consumes=application/json 的接口发 text/plain:POST /json → 415 Unsupported Media Type;org.springframework.web.HttpMediaTypeNotSupportedException ← RequestMappingInfoHandlerMapping.handleNoMatch
  produces=application/json 的接口 Accept: application/xml:GET /prod → 406 ;org.springframework.web.HttpMediaTypeNotAcceptableException ← RequestMappingInfoHandlerMapping.handleNoMatch

在选 Controller 方法阶段就被拒绝,抛出处是 handleNoMatch。

参数绑定

实测 · 本机执行输出
  缺少必填的 @RequestParam:GET /param → 400 Bad Request;org.springframework.web.bind.MissingServletRequestParameterException ← RequestParamMethodArgumentResolver.handleMissingValueInternal
  @RequestParam int 传了 abc:GET /param?n=abc → 400 Bad Request;org.springframework.web.method.annotation.MethodArgumentTypeMismatchException ← AbstractNamedValueMethodArgumentResolver.convertIfNecessary
  @PathVariable int 传了 abc:GET /path/abc → 400 Bad Request;org.springframework.web.method.annotation.MethodArgumentTypeMismatchException ← AbstractNamedValueMethodArgumentResolver.convertIfNecessary
  缺少必填的 @RequestHeader:GET /header → 400 Bad Request;org.springframework.web.bind.MissingRequestHeaderException ← RequestHeaderMethodArgumentResolver.handleMissingValue
  缺少必填的 @CookieValue:GET /cookie → 400 Bad Request;org.springframework.web.bind.MissingRequestCookieException ← AbstractCookieValueMethodArgumentResolver.handleMissingValue
  要表单参数 a 却只发了 b:POST /form → 400 Bad Request;org.springframework.web.bind.MissingServletRequestParameterException ← RequestParamMethodArgumentResolver.handleMissingValueInternal

六种 400,四个异常类。

请求体与其他

实测 · 本机执行输出
  JSON 语法错误:POST /json → 400 Bad Request;org.springframework.http.converter.HttpMessageNotReadableException ← AbstractJacksonHttpMessageConverter.readJavaType
  请求体为空:POST /json → 400 Bad Request;org.springframework.http.converter.HttpMessageNotReadableException ← RequestResponseBodyMethodProcessor.readWithMessageConverters
  @Valid 校验不通过:POST /valid → 400 Bad Request;org.springframework.web.bind.MethodArgumentNotValidException ← RequestResponseBodyMethodProcessor.resolveArgument
  要 multipart 文件却发了表单:POST /mp → 500 Internal Server Error;org.springframework.web.multipart.MultipartException ← RequestParamMethodArgumentResolver.handleMissingValueInternal
  URL 里有非法的百分号编码:GET /%zz → 400 ;(没有进入 Spring MVC 的异常解析)

HttpMessageNotReadableException、校验异常、multipart 的 500,以及 Tomcat 层的 400。

分步演示

状态码
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动(Spring Boot 4.0.8 的 starter-web 与 validation;一个注册在 DispatcherServlet 异常解析器列表最前面、只记录不处理的 HandlerExceptionResolver,记录异常类与栈顶的类和方法;请求用 http.client 直接发)
    • 没有验证:自定义 @ControllerAdvice 与 ProblemDetail 开启后的响应格式;Spring Security 在前面拦截时返回的 401 与 403;HEAD、OPTIONS 请求的处理;文件上传超过大小限制的 413 与 MaxUploadSizeExceededException;WebFlux 里的对应异常;Tomcat 其他层面的 400(例如请求头过大)
    京ICP备2026067502号-1京公网安备11010502063487号