Spring Boot REST API 应使用运行时异常而非受检异常,因其符合框架设计、避免接口污染、支持自动拦截;推荐通过 CommonException 基类 + @RestControllerAdvice 统一处理业务、参数校验和系统异常,并配套枚举码、OpenAPI 文档与 SDK 提升合作方体验。

自定义受检异常(Checked Exception)本身不适用于 Spring Boot 的 REST API 全局异常拦截门面,因为标准实践和框架设计倾向**不使用受检异常作为业务错误传递机制**。真正稳健、干净的 API 接口依赖的是统一的运行时异常体系 + 全局拦截 + 标准响应结构。下面分四块讲清楚怎么做、为什么这么选、关键细节和落地建议:
为什么不用受检异常做 API 错误门面
Java 受检异常要求方法签名显式声明 throws,强制调用方处理。这在 Web 层会带来三个实际问题:
- Controller 方法堆满 throws BusinessException, ValidationException 等,污染接口契约,违背 REST 资源语义
- Spring MVC 不自动捕获受检异常——@ExceptionHandler 默认只处理 RuntimeException 及其子类;若硬要用,需额外注册 HandlerExceptionResolver,增加配置复杂度
- 前端无法区分“业务拒绝”和“系统故障”,因为 HTTP 状态码、响应体结构完全由你手动控制,而受检异常本身不携带状态码或 JSON 字段信息
推荐方案:用运行时异常 + @RestControllerAdvice 构建门面
这是 Spring 生态事实标准,兼顾开发效率、可维护性与客户端友好性:
- 定义一个继承 RuntimeException 的业务异常基类(如 CommonException),带 code、message、status 字段
- 所有业务校验失败、参数非法、权限不足等场景,统一 throw new CommonException(4001, "用户名已存在")
- 编写全局异常处理器类,加 @RestControllerAdvice 注解,内部用 @ExceptionHandler 按类型捕获
- 返回标准响应对象(如 AjaxResult 或 Result
),确保无论抛什么异常,HTTP 状态码、JSON 结构、字段名(code/msg/data/timestamp)全部一致
关键拦截逻辑要覆盖的异常类型
一个完整的门面需同时处理三类错误,不能只盯着业务异常:
- 业务异常:CommonException 及其子类(如 UserNotExistException)→ 返回 400 或 403,code=1001,msg=中文提示
- 参数校验异常:MethodArgumentNotValidException(@Valid)、ConstraintViolationException(@Validated)→ 提取 BindingResult 中的 fieldErrors,组装成统一错误列表
- 系统异常:NullPointerException、SQLException 等 → 记录完整堆栈日志,返回通用 500 错误(code=500,msg="服务暂时不可用"),绝不暴露敏感信息
给合作伙伴提供干净 API 的配套动作
门面只是后端一环,要让合作方真正“开箱即用”,还需同步做几件事:
- 所有异常 code 定义为枚举(如 ErrCodeEnum),每个值明确对应 HTTP 状态码、业务含义、是否可重试
- OpenAPI 3.0 文档中为每个接口的 4xx/5xx 响应补充 examples,展示真实 error body 示例
- 提供 SDK 或 TypeScript 类型定义(基于响应结构生成),让合作方调用时享受 IDE 补全和编译期检查
- 在网关层(如 Spring Cloud Gateway)统一添加 traceId,并透传到异常日志和响应头中,方便合作方提单排查

















