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

时间:2012-06-24 10:52:29

标签: java rest jersey jax-rs

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

例如:

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

1 个答案:

答案 0 :(得分:13)

为了防止出现这种情况,您需要将Jersey客户端配置为对请求使用分块编码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'子组下使用。

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-apache-client</artifactId>
    <version>1.14</version>
</dependency>

接下来,您必须初始化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库不支持指定大小。