发布大文件时,防止Jersey客户端导致outofmemory错误

当使用Jersey客户端将大文件作为InputStream放置时,看起来该文件的整个内容在被发送到服务器之前被缓冲到内存中。 这会导致大文件出现问题,因为JVM的堆空间不足。 如何在Jersey客户端中阻止此行为? 服务器端的JAX-RS资源方法在发送数据时似乎没有这个问题。

例如:

WebResource dataUploadResource = buildDataUploadResource(); dataUploadResource.type(getMimeType()).put(getLargeInputStream()); 

为了防止出现这种情况,您需要将Jersey客户端配置为对请求使用chunked encoding 1 。 这消除了设置Content-Length头的需要,并且将从提供的InputStream流式传输而不缓冲内存中的整个内容。

默认情况下,Jersey使用JDK的HttpURLConection类来处理HTTP请求和响应。 不幸的是,这有一些与分块编码传输有关的错误。 幸运的是,Jersey有扩展点允许使用不同的HTTP客户端实现。 一种这样的实现基于Apache Http Client 2 。

存在两个apache htpp客户端处理程序的实现,一个支持现在的生命周期结束3.x版本,另一个使用较新的4.x版本。 对于我们的项目,我们使用了基于旧版本(3.1)的实现。 该库在Maven Central的’contribs’子组下可用。

  com.sun.jersey.contribs jersey-apache-client 1.14  

接下来,您必须初始化Jersey客户端以使用新的实现:

 Client jerseyClient = ApacheHttpClient.create(getClientConfig()); 

为了启用分块编码,您必须在客户端配置上设置分块编码大小,因为它默认情况下未启用:

 private ClientConfig getClientConfig() { ClientConfig config = new DefaultClientConfig(); config.getProperties().put( DefaultApacheHttpClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 0); return config; } 

只要此属性不为null ,就会使用分块编码。 实际上,版本1.14忽略了编码大小,因为底层apache commons-httpclient库不支持指定大小。