如何使用Apache CloseableHttpAsyncClient上传50GB+大文件?
解决CloseableHttpAsyncClient上传超大文件(50GB+)的问题
核心问题分析
- 使用
FileInputStream构造Multipart实体时,BufferedHttpEntity会将整个文件内容缓冲到内存,直接触发OOM;即使移除BufferedHttpEntity,流方式的实体无法提前计算Content-Length,会抛出“Content Length unknown”错误。 - 直接传入
File调用addBinaryBody方法,会触发HttpClient默认的超大Content-Length校验限制,抛出“Content length is too long”错误。
正确实现方案
要实现超大文件异步上传,需满足三个核心要求:流式传输不加载全文件到内存、绕过Content-Length校验限制、正确配置异步客户端适配大文件传输。
1. 构造流式Multipart实体
使用FileBody直接封装文件,底层基于文件随机访问流实现,不会将整个文件加载到内存:
File file = new File("pathname"); // 用FileBody封装文件,支持流式传输,自动关联文件元信息 FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY, file.getName()); MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); multipartEntityBuilder.addPart("file", fileBody); multipartEntityBuilder.addTextBody("filename", "File one"); HttpEntity multipartEntity = multipartEntityBuilder.build();
2. 配置异步客户端,关闭超大Content-Length校验
HttpClient默认会限制Content-Length不超过Integer.MAX_VALUE(约2GB),需关闭该校验以支持50GB+文件:
// 配置IO线程池 PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager( IOReactorConfig.custom() .setIoThreadCount(Runtime.getRuntime().availableProcessors()) .build() ); // 构建异步客户端,关闭Content-Length校验 HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom() .setConnectionManager(connManager) .disableContentCompression() // 避免压缩带来额外内存开销 .setDefaultRequestConfig(RequestConfig.custom() .setExpectContinueEnabled(true) // 启用100-Continue,先确认服务器接受请求再传文件 .build()); // 关键:关闭Content-Length合法性校验 clientBuilder.setHttpProcessor(new ImmutableHttpProcessor( new RequestContent(false) // 第二个参数设为false,解除超大Content-Length限制 )); CloseableHttpAsyncClient asyncClient = clientBuilder.build(); asyncClient.start();
3. 执行异步上传请求
直接使用构造好的multipartEntity,禁止使用BufferedHttpEntity:
HttpPost postRequest = new HttpPost("http://your-server-url/upload"); postRequest.setEntity(multipartEntity); // 异步执行上传 Future<HttpResponse> future = asyncClient.execute(postRequest, new FutureCallback<HttpResponse>() { @Override public void completed(HttpResponse response) { System.out.println("上传完成,响应状态码:" + response.getStatusLine().getStatusCode()); try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Exception ex) { ex.printStackTrace(); } @Override public void cancelled() { System.out.println("上传被取消"); } }); // 按需等待上传完成(业务场景允许的话可异步处理) future.get(); asyncClient.close();
关键说明
RequestContent(false):彻底关闭HttpClient对Content-Length的大小校验,支持超过2GB的文件传输。FileBody:通过文件随机访问流实现真正的流式上传,内存占用仅为缓冲区大小,不会随文件体积增长。Expect: 100-Continue:让服务器先确认请求合法性,避免大文件传输到一半被拒绝的带宽浪费。
内容的提问来源于stack exchange,提问作者Alessandro Valentino
相关产品推荐
相关产品推荐

