Spring 5.2.5下RestTemplate收500响应抛ResourceAccessException而非HttpServerErrorException问题
RestTemplate调用500接口返回ResourceAccessException丢失响应体解决方案(适配Spring Web 5.2.5)
根因说明
Spring Web 5.2.x版本默认使用SimpleClientHttpRequestFactory作为HTTP请求工厂,当bufferRequestBody配置为false(流式输出请求体)时,若被调用方在没有完全接收完请求体的情况下就返回HTTP 500响应,会触发TCP连接提前关闭,此时RestTemplate会直接抛出ResourceAccessException包装的IO异常,不会进入默认的响应错误解析逻辑,导致响应体数据丢失。
可选解决方案
方案1:开启请求体缓存(轻量改造成本)
关闭流式输出,将请求体全量缓存到内存后再发送,避免连接提前关闭导致的异常类型错乱:
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); // 开启请求体缓存,默认值为true,若之前手动关闭过需改回 requestFactory.setBufferRequestBody(true); RestTemplate restTemplate = new RestTemplate(requestFactory);
注意:该方案适合请求体体积普遍较小的场景,大请求体缓存会占用较多堆内存。
方案2:自定义响应错误处理器
如果不适合开启请求体缓存,可以自定义ResponseErrorHandler,在异常场景下主动读取响应体并封装为标准的HTTP错误异常:
public class CustomRestErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(ClientHttpResponse response) throws IOException { try { super.handleError(response); } catch (ResourceAccessException e) { // 手动读取响应体,封装为HttpServerErrorException抛出 String responseBody = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8); throw new HttpServerErrorException( response.getStatusCode(), response.getStatusText(), response.getHeaders(), responseBody.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8 ); } } }
将自定义处理器注册到RestTemplate:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new CustomRestErrorHandler());
方案3:替换底层HTTP客户端
替换默认的JDK HTTP实现为Apache HttpComponents或者OkHttp,两类客户端不存在流式输出场景下的响应解析异常问题,以Apache HttpComponents为例:
- 引入依赖(Maven示例):
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
- 配置RestTemplate:
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); RestTemplate restTemplate = new RestTemplate(requestFactory);
该方案兼容性和性能表现更好,适合生产环境高并发、请求体大小波动较大的场景。
内容的提问来源于stack exchange,提问作者Kumar
相关产品推荐
相关产品推荐

