Spring REST API错误返回方案对比:ResponseEntity vs 全局异常处理器
RESTful API错误状态码返回方案对比与问题解答
两种核心实现方案
方案一:全局异常处理器 + 自定义异常
通过Spring的@ControllerAdvice定义全局异常处理器,捕获业务层抛出的特定自定义异常,统一封装错误响应返回。
全局异常处理器代码:
@ControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler public ResponseEntity<AppError> catchResourceNotFoundException(ResourceNotFoundException e) { log.error(e.getMessage(), e); return new ResponseEntity<>(new AppError(HttpStatus.NOT_FOUND.value(), e.getMessage()), HttpStatus.NOT_FOUND); } }
对应Controller代码:
@GetMapping("/products") public Product getProduct(Long id){ return productsService.findById(id); }
Service代码:
public Product findById(Long id) { return productsRepository.findById(id).orElseThrow( () -> new ResourceNotFoundException("Product with id " + id + " not found")); }
方案二:直接使用ResponseEntity封装响应
在Controller方法中直接通过ResponseEntity封装成功或失败的响应结果,包含HTTP状态码和响应体。
Controller代码示例:
@GetMapping("/products") public ResponseEntity<?> getProduct(Long id){ try { Product product = productsService.findById(id).orElseThrow(); return new ResponseEntity<>(product, HttpStatus.OK); } catch (Exception e){ return new ResponseEntity<>(new AppError(HttpStatus.NOT_FOUND.value(), "Product with id " + id + " not found"), HttpStatus.NOT_FOUND); } }
问题解答
1. 哪种方案更优?原因是什么?
全局异常处理器的方案更优,核心原因如下:
- 代码解耦与简洁:Controller只需专注业务逻辑,不用在每个接口中重复编写try-catch和响应封装代码,减少冗余。
- 统一管控:所有异常处理逻辑集中在一处,方便统一调整错误响应格式、日志记录规则,避免多处修改。
- 业务语义明确:自定义异常能精准表达业务错误场景(如
ResourceNotFoundException直接标识资源不存在),比笼统捕获Exception更具可读性和维护性。 - 扩展性强:新增异常类型时,只需添加对应的自定义异常和全局处理器中的
@ExceptionHandler方法,无需改动多个Controller。
2. 若优先选择ResponseEntity方案,在Android Kotlin的Retrofit中接收是否困难?服务端(Java Spring)发送的ResponseEntity在Kotlin端会被解析为何种类型?
完全不困难,Retrofit可以轻松处理这类响应:
- Spring的
ResponseEntity本质是携带HTTP状态码的JSON响应:请求成功时返回Product结构的JSON,失败时返回AppError结构的JSON。 - 在Kotlin端,你只需定义对应的数据类:
data class Product(val id: Long, val name: String, ...) data class AppError(val code: Int, val message: String) - 接口定义时使用Retrofit的
Response<T>来接收,比如:@GET("/products") suspend fun getProduct(@Query("id") id: Long): Response<Product> - 调用时通过
response.isSuccessful判断状态:成功则解析response.body()得到Product实例;失败则将response.errorBody()转换为AppError实例(可借助Gson、Moshi等序列化工具完成)。
内容的提问来源于stack exchange,提问作者Crystal2033
相关产品推荐
相关产品推荐

