接口少传必填参数时,HTTP 状态是 400,响应体却为空,先看异常被哪个 HandlerExceptionResolver 处理。返回了错误状态,不代表一定会经过 Spring Boot 的 /error 并生成同一种 JSON。
继承异常处理基类会改变处理路径
旧工程的全局异常类继承了 ResponseEntityExceptionHandler。缺少请求参数时,异常进入该类的处理方法,而不是自己预期的其他兜底分支。
这不等于“Spring Boot 默认一定返回 JSON,继承后才出错”。MVC 异常解析链、已注册 Advice 和容器错误分发共同影响最终响应;只移除 extends,也不能保证所有场景都得到相同结构。
为具体异常明确设置响应体
下面使用 Spring Framework 5.3 方法签名,定制 MissingServletRequestParameterException:
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@RestControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(
MissingServletRequestParameterException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("code", "MISSING_PARAMETER");
body.put("message", "缺少必填请求参数");
body.put("parameter", ex.getParameterName());
return new ResponseEntity<Object>(body, headers, status);
}
}
它保留框架给出的状态和响应头,提供稳定的业务错误体,不直接向客户端返回内部堆栈。Spring 5.3 对应 API
Spring 6 的对应方法使用 HttpStatusCode 等新签名,升级时应以所用版本 API 为准,不能原样粘贴后再删除 @Override 掩盖不匹配。
如何区分没有进入方法和响应又被改写
以必须接收 @RequestParam(“value”) 的接口为例,故意省略 value,观察三件事:是否到达指定处理方法、HTTP 状态是否仍为 400、原始响应体是否是约定结构。若还有统一返回包装或多个 Advice,要继续检查其作用范围及顺序。
同时检查正常请求、其他业务异常和不支持的请求方法,避免只修一条错误路径却破坏整个异常协议。关于 JSON 转换器选择,另见注解与 MVC 消息转换器。