Spring RestTemplate exchange非200响应抛出HttpClientException问题
这个问题其实是RestTemplate的默认行为导致的——它的默认错误处理器会在收到**4xx(客户端错误)或5xx(服务端错误)**状态码时直接抛出异常,而不是把完整响应返回给你处理。你看到异常里显示响应体为null,其实是异常的默认输出误导了你,异常对象本身是包含响应体、状态码和响应头的。
下面给你两种实用的解决思路,按需选择:
方法1:捕获异常并提取响应信息
如果只是个别请求需要处理非200响应,最简单的方式就是在调用exchange时包裹try-catch块,直接从异常对象里提取你需要的响应内容。
修改后的客户端代码示例:
public String callFruitBasket(Fruit fruitRequest) { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Fruit> fruit = new HttpEntity<>(fruitRequest, requestHeaders); System.out.println("Fruit headers: " + fruit.getHeaders()); try { ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class); System.out.println("Full response: " + response); return response.getBody(); } catch (HttpClientErrorException e) { // 处理4xx类型的错误响应 System.out.println("Error status code: " + e.getStatusCode()); System.out.println("Error response headers: " + e.getResponseHeaders()); String errorBody = e.getResponseBodyAsString(); System.out.println("Error response body: " + errorBody); // 根据业务需求返回错误体或自定义内容 return errorBody; } catch (HttpServerErrorException e) { // 处理5xx类型的服务端错误 System.out.println("Server error status code: " + e.getStatusCode()); return e.getResponseBodyAsString(); } }
方法2:自定义错误处理器(全局生效)
如果你的项目里大部分请求都需要处理非200响应,不想每次都写重复的try-catch,可以自定义一个ResponseErrorHandler,让RestTemplate遇到非200状态时不抛出异常,直接返回完整响应。
第一步:创建自定义错误处理器
import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.DefaultResponseErrorHandler; import java.io.IOException; public class CustomResponseErrorHandler extends DefaultResponseErrorHandler { @Override public boolean hasError(ClientHttpResponse response) throws IOException { // 返回false表示所有状态码都不视为"错误",不会触发异常抛出 // 如果你只想忽略特定状态码,可以在这里做判断,比如: // return super.hasError(response) && !response.getStatusCode().is4xxClientError(); return false; } @Override public void handleError(ClientHttpResponse response) throws IOException { // 因为hasError返回false,这个方法不会被调用,留空即可 } }
第二步:给RestTemplate绑定这个处理器
在你初始化RestTemplate的配置类或代码块里添加:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new CustomResponseErrorHandler());
之后再调用exchange,不管是200、400还是404,都会返回完整的ResponseEntity,你可以按需判断状态码处理:
public String callFruitBasket(Fruit fruitRequest) { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Fruit> fruit = new HttpEntity<>(fruitRequest, requestHeaders); System.out.println("Fruit headers: " + fruit.getHeaders()); ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class); System.out.println("Full response: " + response); // 根据状态码分支处理 if (response.getStatusCode().is2xxSuccessful()) { return response.getBody(); } else { System.out.println("Non-success status: " + response.getStatusCode()); return response.getBody(); } }
补充说明
- 你之前看到的异常信息里的
response body null只是异常默认toString()的输出形式,实际HttpClientErrorException对象里是存储了完整响应体的,调用getResponseBodyAsString()就能获取到。 - 两种方法各有适用场景:方法1适合局部请求的特殊处理,方法2适合全局统一处理非200响应的需求。
内容的提问来源于stack exchange,提问作者iranicus
相关产品推荐
相关产品推荐

