Springboot RestTemplate调用大数据时抛出Unexpected end of file异常
异常原因
- RestTemplate默认使用
SimpleBufferingClientHttpRequest请求工厂,基于JDK自带的HttpURLConnection实现,采用全量缓冲模式:会先把完整的响应体全部加载到JVM内存后再返回给业务代码。当响应体达到100MB级别时,要么服务A内存不足触发长时间GC甚至OOM,迟迟无法读取Socket数据,要么服务B等待客户端读取超时主动断开连接,最终A端抛出SocketException: Unexpected end of file from server,B端抛出IOException: Broken pipe。 - 服务B内嵌Web服务器(如Tomcat)默认存在响应大小、传输超时限制,大体积数据传输时超过阈值被服务器主动断连。
- 中间链路的负载均衡、API网关、防火墙等设备存在超时或最大传输包限制,大流量传输过程中被中间设备主动切断连接。
解决方案
1. 替换RestTemplate请求工厂,启用流式传输
更换为支持非缓冲、流式传输的请求工厂,比如基于Apache HttpClient的HttpComponentsClientHttpRequestFactory,避免一次性加载全量响应到内存:
首先引入Apache HttpClient依赖(Maven示例):
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
修改RestTemplate配置:
public RestTemplate restTemplate(final RestTemplateBuilder builder) { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); // 连接超时15分钟,单位毫秒 requestFactory.setConnectTimeout(900000); // 读取超时15分钟,单位毫秒 requestFactory.setReadTimeout(900000); // 关闭请求缓冲,启用流式传输 requestFactory.setBufferRequestBody(false); return builder .requestFactory(() -> requestFactory) .build(); }
2. 调整服务B的Web服务器配置
以内嵌Tomcat为例,在application.yml中放开大小和超时限制:
server: tomcat: # 不限制请求/响应最大大小 max-swallow-size: -1 # 连接超时设为15分钟 connection-timeout: 900000 # 不限制表单POST大小 max-http-form-post-size: -1
3. 调整服务A的JVM内存配置
增大服务A的堆内存,保证有足够空间处理大体积JSON,启动参数示例:
-Xms2G -Xmx4G
4. 调整中间链路配置
如果存在负载均衡、API网关、防火墙等中间设备,对应调整设备的超时时间和最大传输数据量阈值,避免中间设备主动断连。
5. 可选优化:开启传输压缩
服务B开启HTTP响应GZIP压缩,大幅降低传输数据量,减少超时概率,配置示例:
server: compression: enabled: true # 大于1KB的响应就开启压缩 min-response-size: 1024 mime-types: application/json
6. 极端场景优化
如果数据量还会持续增长,建议改成分页拉取、或文件分片下载的方案,避免单次请求传输过大体积数据。
内容的提问来源于stack exchange,提问作者skc
相关产品推荐
相关产品推荐

