Spring Boot服务调用中错误状态码ResponseEntity引发调用方异常咨询
问题根源
这其实是RestTemplate的默认行为搞的鬼:当被调用服务返回4xx/5xx这类错误状态码时,RestTemplate不会直接把带错误状态的ResponseEntity返回给你,而是会抛出对应的异常——4xx错误抛HttpClientErrorException,5xx错误抛HttpServerErrorException,所以你的调用方代码才会总是进入异常分支。
解决方案
下面给你几种实用的处理方式,按需选择就行:
1. 直接捕获异常提取错误信息
最省事的方式就是在调用代码里把这些异常接住,从异常对象里掏出来你需要的错误响应内容、状态码和headers:
ResponseEntity<String> responseEntity; try { responseEntity = restTemplate.postForEntity(url, entity, String.class); // 处理正常的2xx响应逻辑 } catch (HttpServerErrorException e) { // 专门处理5xx错误,比如你遇到的INTERNAL_SERVER_ERROR String errorJson = e.getResponseBodyAsString(); // 拿到被调用方返回的jsonString HttpStatus errorStatus = e.getStatusCode(); HttpHeaders errorHeaders = e.getResponseHeaders(); // 这里就可以解析errorJson做后续处理了 } catch (HttpClientErrorException e) { // 处理4xx错误,比如400参数错误、404资源不存在等 String errorJson = e.getResponseBodyAsString(); // 按需处理 } catch (RestClientException e) { // 兜底捕获其他RestClient相关异常 e.printStackTrace(); }
2. 自定义ErrorHandler让RestTemplate不抛异常
如果你希望不管响应状态是成功还是失败,RestTemplate都直接返回ResponseEntity而不炸锅,可以自定义一个ResponseErrorHandler来覆盖默认行为:
第一步:写自定义ErrorHandler类
import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.DefaultResponseErrorHandler; import java.io.IOException; public class NoThrowErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(ClientHttpResponse response) throws IOException { // 这里啥都不做(或者只记录个日志),就是不抛出异常 // 比如加个日志:log.warn("收到错误响应: {} - {}", response.getStatusCode(), response.getStatusText()); } @Override public boolean hasError(ClientHttpResponse response) throws IOException { // 保持默认的错误判断逻辑(4xx/5xx算错误),但就是不抛异常 HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode()); return statusCode != null && statusCode.isError(); } }
第二步:给RestTemplate装上这个ErrorHandler
如果是用配置类创建RestTemplate的:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new NoThrowErrorHandler()); return restTemplate; } }
如果是直接new RestTemplate实例的:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new NoThrowErrorHandler());
搞定之后,再调用postForEntity,哪怕对方返回500,也会正常返回包含错误内容、状态码的ResponseEntity,你就可以像处理正常响应一样,用responseEntity.getStatusCode()判断状态,再拿getBody()取错误json了。
3. 用exchange方法(更灵活的可选方案)
其实postForEntity底层也是调用exchange,如果你需要自定义请求头、请求方法这些更灵活的配置,也可以用exchange配合上面的自定义ErrorHandler,效果完全一样:
// 先组装请求实体 HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> requestEntity = new HttpEntity<>("你的请求体内容", requestHeaders); // 调用接口 ResponseEntity<String> responseEntity = restTemplate.exchange( url, HttpMethod.POST, requestEntity, String.class ); // 直接判断状态码处理 if (responseEntity.getStatusCode().is2xxSuccessful()) { // 正常逻辑 } else { String errorJson = responseEntity.getBody(); // 处理错误 }
小提醒
- 用自定义ErrorHandler的时候,记得加日志记录错误情况,不然出问题了连排查线索都没有。
- 捕获异常的方式适合只在个别调用点处理错误的场景,自定义ErrorHandler更适合全局统一处理的场景。
内容的提问来源于stack exchange,提问作者Hary
相关产品推荐
相关产品推荐

