如何通过RestTemplate上传大文件?2GB以上文件报ArrayIndexOutOfBoundsException
解决方案:RestTemplate转发大文件(>2GB)的数组越界及501编码问题
一、解决ArrayIndexOutOfBoundsException(大文件数组越界)
问题原因
默认RestTemplate使用AbstractBufferingClientHttpRequest,会将整个请求体缓冲到FastByteArrayOutputStream中。而Java字节数组的最大长度为Integer.MAX_VALUE(约2GB),当文件超过该阈值时,就会触发数组越界异常。
解决步骤
替换RestTemplate的请求工厂为非缓冲类型,比如Apache HttpClient的HttpComponentsClientHttpRequestFactory,它支持流式传输,无需将整个文件加载到内存:
- 添加Apache HttpClient依赖(Maven示例):
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.3</version> </dependency>
- 重新配置RestTemplate,使用非缓冲请求工厂:
@Bean public RestTemplate largeFileRestTemplate() { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault()); // 禁用请求体缓冲,启用流式传输 factory.setBufferRequestBody(false); RestTemplate restTemplate = new RestTemplate(factory); // 按需保留日志拦截器 restTemplate.setInterceptors(Collections.singletonList(new LoggingInterceptor())); return restTemplate; }
- 调整上传代码,传递文件准确长度(避免分块编码):
如果从MultipartFile获取文件,直接传递输入流和文件大小:
protected String postFileRestTemplate(String addToBaseURL, MultipartFile file) throws IOException { httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); MultipartBodyBuilder builder = new MultipartBodyBuilder(); builder.part("content", "iso"); // 传递流时指定文件长度,让HttpClient自动设置Content-Length builder.part("filename", file.getInputStream(), file.getSize()); MultiValueMap<String, HttpEntity<?>> build = builder.build(); HttpEntity<Object> objectHttpEntity = new HttpEntity<>(build, httpHeaders); ResponseEntity<String> exchange = restTemplate.postForEntity( baseURL + addToBaseURL, objectHttpEntity, String.class); log.info(exchange.getBody()); return exchange.getBody(); }
二、解决"501 chunked transfer encoding not supported"错误
问题原因
移除LoggingInterceptor后,默认请求工厂会自动启用分块编码(chunked),但目标API不支持该传输方式。而日志拦截器可能因提前读取请求体,触发了RestTemplate自动缓冲,从而绕过了分块编码。
解决步骤
结合上述非缓冲请求工厂配置,同时确保请求能正确设置Content-Length头:
- 使用
HttpComponentsClientHttpRequestFactory并禁用缓冲后,只要传递了文件的准确长度,HttpClient会自动生成Content-Length头,避免使用分块编码。 - 如果无法获取文件长度(如流来自网络),需让目标API升级支持分块编码,或改用其他大文件传输协议(如FTP)。
关键注意事项
- 优先使用Apache HttpClient的请求工厂,而非默认的
SimpleClientHttpRequestFactory,前者对大文件流式传输的支持更稳定。 - 必须确保传递给
MultipartBodyBuilder.part()的资源包含准确长度,否则仍会触发分块编码。
内容的提问来源于stack exchange,提问作者Konstantin Panisov
相关产品推荐
相关产品推荐

