统一异常处理的目标是稳定 HTTP 状态、机器可读错误码和请求标识,而不是把所有错误都变成 200。不同层只能处理自己看得到的失败。
Table of contents
Open Table of contents
运行错误协议样例
ApiExceptionHandler下载把参数错误转换为 RFC 9457 风格 ProblemDetail:
{
"title": "请求参数错误",
"status": 400,
"detail": "name 不能为空",
"code": "INVALID_ARGUMENT"
}
运行控制器和异常处理测试:
mvn -Dtest=SpringSourceLabTest#mvcMapsGreetingController test
三类扩展点的范围
| 扩展点 | 位置 | 适合用途 |
|---|---|---|
| Servlet Filter | DispatcherServlet 外 | 请求 ID、基础安全头、原始请求包装 |
| HandlerInterceptor | 控制器映射后 | Handler 相关鉴权、审计 |
| ControllerAdvice | 控制器调用异常 | 业务异常到 HTTP 错误转换 |
Filter 抛出的异常通常到不了 ControllerAdvice,需要容器级错误处理。Interceptor 的 afterCompletion 适合清理,但异步请求还要理解二次分派。
请求 ID 必须贯穿响应
RequestIdFilter下载接受可信请求 ID 或生成新值,并写回响应头。
生产实现还要验证长度与字符集,写入日志 MDC,并在 finally 清理线程上下文。
不要泄露内部异常
对客户端返回稳定 code 和安全描述,对日志保留完整堆栈、请求 ID 和必要上下文。SQL、文件路径、令牌和个人信息不能直接进入响应。
为 400、401、403、404、409、422、429 和 5xx 分别建立契约测试。未知异常返回 500;不要把所有 RuntimeException 归类成“参数错误”。
下一步
阅读Spring 与 MyBatis 的整合机制,理解 Mapper 接口如何成为 Bean 并加入同一事务。