spring boot全局异常处理需用@restcontrolleradvice捕获exception.class,返回responseentity.status(500).body(r.fail(500,"系统繁忙")),确保http状态码真实为500且json结构统一,避免吞error、区分业务异常与系统异常,并记录堆栈不暴露敏感信息。

Spring Boot 全局异常处理中统一封装 500 错误,核心不是“只改状态码”,而是让 所有未预期的服务器异常 都返回你定义的标准业务结构(如 {"code":500,"message":"系统繁忙,请稍后再试","data":null}),同时 HTTP 响应头里真实携带 500 Internal Server Error 状态码——这样前后端约定才真正生效。
用 @RestControllerAdvice 捕获所有未处理异常
创建一个全局异常处理器类,用 @RestControllerAdvice 标记,它会自动作用于所有 @RestController 或 @Controller 方法抛出的异常:
- 不要只写
@ControllerAdvice+@ResponseBody,直接用@RestControllerAdvice更简洁,省去重复加@ResponseBody的麻烦; - 推荐捕获
Exception.class作为兜底,覆盖空指针、数据库连接失败、JSON序列化异常等一切非业务显式抛出的错误; - 避免捕获
Throwable(含Error),比如OutOfMemoryError不该被业务层“吞掉”并返回 500 JSON,而应让 JVM 或容器介入。
返回 ResponseEntity,兼顾 JSON body 和 HTTP 状态码
关键点在于:不能只返回 R.fail(...) 对象,必须用 ResponseEntity 包装,才能精确控制响应头中的 status:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 使用
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.fail(500, "系统内部错误")); - 这样前端收到的不仅是标准 JSON,HTTP 状态码也是真实的 500,便于网关、监控、前端拦截器识别;
- 如果只返回
R对象(即使加了@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)),Spring Boot 默认仍会设为 200,除非显式用ResponseEntity或@ResponseStatus注解在方法上——但后者无法动态设 message,灵活性差。
区分“真 500”和“伪 500”,避免掩盖业务意图
有些团队把所有异常都塞进 500,导致日志和监控无法区分是代码 bug 还是临时故障。建议分层处理:
- 对
RuntimeException及子类(如NullPointerException、IllegalArgumentException)默认返回 500 —— 它们往往反映开发疏漏或数据异常,需告警; - 对自定义业务异常(如
UserNotExistException),应单独用@ExceptionHandler方法处理,并返回更合适的状态码(如 404)和业务 code(如 1002); - 兜底的
Exception处理器只做两件事:记录完整堆栈(打到日志)、返回统一 R 结构 + 500 状态码,不暴露敏感信息(如数据库表名、路径)。
配合统一响应体 R 类,保持结构一致性
确保你的 R<t></t> 类已定义好静态工厂方法,例如:
-
R.fail(500, "服务暂时不可用")—— 明确指定 code 和 message; - 避免在异常处理器里拼接字符串或硬编码 message,可引入国际化或错误码配置中心;
- data 字段始终为
null(500 是服务端错误,一般不传业务数据),避免误导前端解析。










