适用读者:要把一个接口"做完整"的人。
前置:S07-B04、S07-B05。
实测环境:Spring Boot 3.3.6 / JDK 17(2026-11-05)。
覆盖旧文:327(77) 330(58) 328(57) 326(61) 324(58) 493(37) 1746(82) 1754(101) 505(37) 473(40) 1755(66) 401(628) = 1,302 点。
覆盖扩展:E-S07-010(统一响应与全局异常)。
上一篇:S07-B05 · Spring Boot:自动配置与启动流程
下一篇:S07-J01 · 事务传播与失效。
1. 一句话结论
一个"能上线"的接口需要五件套:参数校验、统一响应、全局异常、可追踪日志、可查的文档/监控。缺一个,线上就会以某种方式咬你。
| 组件 | 缺失后果 |
|---|---|
| 参数校验 | 脏数据进库 |
| 统一响应 | 前端要兼容多种结构 |
| 全局异常 | 500 带堆栈泄露 |
| 链路日志 | 排障时找不到一次请求的完整日志 |
| 文档/监控 | 联调靠猜、故障靠用户反馈 |
2. 实测:校验失败返回什么
[HTTP 400] {"errors":[{"msg":"must not be blank","field":"name"},
{"msg":"must be less than or equal to 120","field":"age"}]}
对比 S10(FastAPI):FastAPI 返回 422,Spring 返回 400——两者语义都指"请求不合法",但前端要按框架区分(跨语言服务共存时要统一)。
合法请求:
[HTTP 201] {"age":30,"name":"张三"}
3. 统一响应 + 全局异常(E-S07-010)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> onInvalid(MethodArgumentNotValidException e) {
var errs = e.getBindingResult().getFieldErrors().stream()
.map(f -> Map.of("field", f.getField(), "msg", f.getDefaultMessage())).toList();
return ResponseEntity.badRequest().body(Map.of("errors", errs));
}
}
| 原则 | 说明 |
|---|---|
| 不返回堆栈 | 泄露内部结构 |
| 错误码可区分 | 业务码 + HTTP 状态码双轨 |
| 字段级错误 | 前端能定位到具体字段 |
实测:上面那段 @RestControllerAdvice 就是产出 §2 那段 JSON 的代码。
4. 日志:MDC 链路追踪(A-326/A-324/A-493)
MDC.put("traceId", UUID.randomUUID().toString().substring(0, 8));
try { /* 业务 */ } finally { MDC.clear(); } // ← 必须清理(线程池!)
| 点 | 说明 |
|---|---|
logback-spring.xml |
在 pattern 里加 %X{traceId} |
| 线程池 | 不清理会串号(同 S05-B04 的 ThreadLocal 泄漏) |
| 异步任务 | 要显式传递 MDC(TaskDecorator) |
判据:"能在一次请求的所有日志里 grep 到同一个 traceId 吗?" 不能 → 链路日志没做好。
5. 文档与监控(A-1754/A-505/A-473)
| 工具 | 用途 | 注意 |
|---|---|---|
| springdoc-openapi | 生成 OpenAPI(Swagger UI 的现代替代) | Spring Boot 3 用 springdoc-openapi-starter-webmvc-ui |
| Knife4j | 增强 UI | 与 springdoc 版本要匹配 |
| Spring Boot Admin | 多实例监控面板 | 需要 actuator |
| Actuator | 健康/指标/环境 | 生产要限制端点暴露 |
安全提醒:management.endpoints.web.exposure.include=* 在生产等于把内部信息公网暴露。
6. HTTP 客户端:RestTemplate(A-401,628 点)
| 客户端 | 状态 |
|---|---|
RestTemplate |
维护模式(仍可用) |
WebClient |
响应式推荐 |
RestClient(Boot 3.2+) |
同步场景的新推荐 |
判据:新项目同步调用用 RestClient;已在 WebFlux 栈用 WebClient;老项目继续 RestTemplate。
7. 五个误区
| 误区 | 真相 |
|---|---|
| "全局异常处理只是少写 try-catch" | 它决定对外错误契约 |
| "MDC 会自动清理" | 线程池必须手动 |
| "Swagger UI 直接上生产" | 会暴露接口全貌,需鉴权 |
| "actuator 全开更方便" | 泄露环境/配置 |
| "Spring 与 FastAPI 错误码一致" | 400 vs 422(实测) |
8. 自检
- "能上线的接口五件套"是什么?
- Spring 的
@Valid失败返回什么状态码?FastAPI 呢? - 全局异常处理的三条原则?
- MDC 为什么必须清理?异步任务怎么传?
- 生产环境 actuator 该怎么配?
9. 下一篇
S07-J01 · 事务:传播机制与失效的六种原因
基础层到此结束。进阶层第一篇讲 Spring 最容易被讲成玄学的部分:事务为什么"不生效"。
本篇属于系列《S07 · Spring 框架》。旧文来源:A-327/330/328/326/324/493/1746/1754/505/473/1755/401;扩展点 E-S07-010。400/201 响应为 Spring Boot 3.3.6 实测。