Spring RestClient遇IOException/ResourceAccessException时如何读取响应体?
问题:使用RestClient发送请求时无法读取400错误的响应体
我用RestClient(不是RestTemplate)调用其他服务器接口,因缺少请求头返回400错误,但程序里读不到响应体。用Postman请求能拿到内容为"header XY missing"的响应,现在需要在程序中获取该错误信息,找到读取/记录响应体的方法。
现有代码实现
1. 请求方法代码
public boolean myMethod(String body, String baseUrl, String token) { return restClient.post() .uri(baseUrl + "/myEndpoint") .headers( httpHeaders -> { httpHeaders.set("Calling-Application", "IGPR"); httpHeaders.set("Content-Type", "application/json"); httpHeaders.set("Locale", "deu-DEU"); httpHeaders.set("Authorization", "Bearer " + token); }) .body(body) .exchange((req, res) -> { try { if (res.getStatusCode().is2xxSuccessful()) { return true; } } catch (HttpClientErrorException e) { e.printStackTrace(); } catch (IOException re) { // 这里不生效! System.out.println(res.getBody()); } return false; }); }
2. 日志拦截器代码
public class RequestResponseLoggingInterceptor implements ClientHttpRequestInterceptor { private final Logger log = LoggerFactory.getLogger(this.getClass()); @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { logRequest(request, body); ClientHttpResponse response = execution.execute(request, body); BufferedClientHttpResponseWrapper responseWrapper = new BufferedClientHttpResponseWrapper(response); logResponse(responseWrapper); return responseWrapper; } private void logRequest(HttpRequest request, byte[] body) throws IOException { log.debug("===========================request begin================================================"); log.debug("URI : {}", request.getURI()); log.debug("Method : {}", request.getMethod()); log.debug("Headers : {}", request.getHeaders()); log.debug("Request body: {}", new String(body, StandardCharsets.UTF_8)); log.debug("==========================request end================================================"); } private void logResponse(ClientHttpResponse response) throws IOException { log.debug("============================response begin=========================================="); log.debug("Status code : {}", response.getStatusCode()); log.debug("Status text : {}", response.getStatusText()); log.debug("Headers : {}", response.getHeaders()); log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset())); log.debug("=======================response end================================================="); } }
3. 响应包装类代码
public class BufferedClientHttpResponseWrapper implements ClientHttpResponse { private final ClientHttpResponse response; private byte[] body; public BufferedClientHttpResponseWrapper(ClientHttpResponse response) throws IOException { this.response = response; this.body = StreamUtils.copyToByteArray(response.getBody()); } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream(body); } @Override public String getStatusText() throws IOException { return response.getStatusText(); } @Override public void close() { response.close(); } @Override public org.springframework.http.HttpHeaders getHeaders() { return response.getHeaders(); } @Override public HttpStatusCode getStatusCode() throws IOException { return response.getStatusCode(); } }
解决方案
1. 在exchange回调中直接读取错误响应体
原代码的HttpClientErrorException捕获逻辑不生效,因为RestClient的exchange回调不会自动抛出该异常,需手动读取响应体:
修改后的请求方法:
public boolean myMethod(String body, String baseUrl, String token) { return restClient.post() .uri(baseUrl + "/myEndpoint") .headers(httpHeaders -> { httpHeaders.set("Calling-Application", "IGPR"); httpHeaders.set("Content-Type", "application/json"); httpHeaders.set("Locale", "deu-DEU"); httpHeaders.set("Authorization", "Bearer " + token); }) .body(body) .exchange((req, res) -> { HttpStatusCode statusCode = res.getStatusCode(); if (statusCode.is2xxSuccessful()) { return true; } else { // 读取错误响应体 String errorBody = StreamUtils.copyToString(res.getBody(), StandardCharsets.UTF_8); System.err.println("错误响应内容:" + errorBody); // 可根据业务需求抛出自定义异常或做其他处理 throw new RuntimeException("请求失败:" + errorBody); } }); }
2. 修复日志拦截器不生效问题
拦截器未生效大概率是因为没注册到RestClient实例中,创建RestClient时需添加拦截器:
RestClient restClient = RestClient.builder() // 可选:设置基础URL .baseUrl("your-base-url") // 注册日志拦截器 .interceptors(new RequestResponseLoggingInterceptor()) .build();
另外,确保日志级别设置为DEBUG,否则log.debug的内容不会输出。可在application.properties中配置:
logging.level.com.your.package.RequestResponseLoggingInterceptor=DEBUG
内容的提问来源于stack exchange,提问作者OnDemand
相关产品推荐
相关产品推荐

