防止 Jersey 客户端在发布大文件时导致内存不足错误客户端、大文件、错误、内存不足

2023-09-06 15:15:58 作者:我在未来等你

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

When positing large files as an InputStream using the Jersey client, it appears that the entire contents of the file is being buffered into memory before being sent to the server. This causes a problem with large files as the JVM runs out of heap space. How do I prevent this behaviour in the Jersey client? JAX-RS resource methods on the server side don't seem to have this problem when sending data.

例如:

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

推荐答案

为了防止这种行为,您需要将 Jersey 客户端配置为使用分块编码1 用于请求.这消除了设置 Content-Length 标头的需要,并且将从提供的 InputStream 流式传输,而无需缓冲内存中的全部内容.

In order to prevent this behaviour you need configure the Jersey client to use chunked encoding1 for the request. This removes the need to set a Content-Length header and will stream from the the supplied InputStream without buffering the entire contents in memory.

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

By default Jersey uses the JDK's HttpURLConection class to handle HTTP requests and responses. Unfortunately this has some bugs related to chunked encoding transfers. Fortunately, Jersey has extension points to allow different HTTP client implementations to be used. One such implementation is based on the Apache Http Client2.

存在两种 apache htpp 客户端处理程序实现,一种支持现已停产的 3.x 版本,另一种使用较新的 4.x 版本.对于我们的项目,我们使用了基于旧 (3.1) 版本的实现.该库位于 Maven Central 中的contribs"子组下.

Two implementations of the apache htpp client handler exist, one supports the now end of life 3.x version, the other uses the newer 4.x version. For our project we used implementation based on the older (3.1) version. The library is available in Maven Central under the 'contribs' sub-group.

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

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

Next you have to initialise your Jersey client to use the new implementation:

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

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

In order to enable chunked encoding, you'll have to set the chunked encoding size on the client configuration as it's not enabled by default:

private ClientConfig getClientConfig() {
   ClientConfig config = new DefaultClientConfig();

   config.getProperties().put(
            DefaultApacheHttpClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 0);
   return config;
}

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

As long as this property is not null, chunked encoding will be used. In fact, version 1.14 ignores the encoding size as specifying a size is not supported by the underlying apache commons-httpclient library.

 
精彩推荐
图片推荐