发布大文件时,防止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库不支持指定大小。