如何让 Jersey 对响应消息正文使用 GZip 压缩消息、正文、Jersey、GZip

2023-09-06 11:41:27 作者:被窝探险家

我正在尝试编写一个简单的 Jersey 应用程序,将文件从 Jersey 客户端发送到 Jersey 服务器并返回.但是,这些文件似乎只在从客户端到服务器的过程中被编码,而不是在其他方式.我想知道如何改变这种行为.

I am trying to write a simple Jersey application that sends files from a Jersey client to a Jersey server and back. However, the files only seem to be encoded on the way from the client to the server but not the other way. I wonder how I can change this behavior.

我在一个简单的例子中对此进行测试:

I am testing this in a simple example:

public class GZipEncodingTest extends JerseyTest {

  private static final String PATH = "/";
  private static final String QUESTION = "foo", ANSWER = "bar";
  private static final String ENCODING_GZIP = "gzip";

  @Path(PATH)
  public static class MyResource {
    @POST
    public Response handle(String question) throws IOException {
      assertEquals(QUESTION, question);
      return Response.ok(ANSWER).build(); // (1)
    }
  }

  @Override
  protected Application configure() {
    enable(TestProperties.LOG_TRAFFIC);
    enable(TestProperties.DUMP_ENTITY);
    return new ResourceConfig(MyResource.class, GZipEncoder.class);
  }

  @Override
  @SuppressWarnings("unchecked")
  protected void configureClient(ClientConfig config) {
    config.register(new EncodingFeature(ENCODING_GZIP, GZipEncoder.class));
  }

  @Test
  public void testHeaders() throws Exception {
    Response response = target().path(PATH).request().post(Entity.text(QUESTION));
    assertEquals(ANSWER, response.readEntity(String.class));
  }
}

从记录的转储中,我可以看出请求符合预期:内容编码在标头中发出信号并应用于请求消息正文.Accept-Encoding 也已设置.服务器了解应用的 gzip 压缩并解压缩请求消息正文.但是,它忽略了客户端接受压缩后的响应并发送未压缩的响应消息体这一事实.

From the logged dump, I can tell that the request is as intended: the content encoding is signaled in the header and applied on the request message body. The Accept-Encoding is also set. The server understands the applied gzip compression and unzips the request message body. However, it ignores the fact that the client accepts a gzipped response and sends the response message body uncompressed.

当我在 Response-builder 链的 (1) 行中附加 encoding(ENCODING_GZIP) 时,我得到了我正在寻找的结果为了.但是,我只想在请求中将其标记为可接受的情况下应用编码.此外,我想在整个应用程序范围内联合此功能,而不仅仅是针对特定响应.

When I append encoding(ENCODING_GZIP) in line (1) in the Response-builder chain, I get the result I am looking for. However, I want to only apply the encoding if it was marked as acceptable in the request. Furthermore, I want to ally this feature application wide and not only for specific responses.

我当然可以使用 WriterInterceptor 手动添加这样的功能:

I can of course add such a feature manually with a WriterInterceptor:

public class GZipWriterInterceptor implements WriterInterceptor {
  @Override
  public void aroundWriteTo(WriterInterceptorContext context) 
      throws IOException, WebApplicationException {
    context.getHeaders().add(HttpHeaders.CONTENT_ENCODING, ENCODING_GZIP);
    context.proceed();
  }
}

但我确信这是不必要的样板.

but I am convinced that this is unnecessary boiler plate.

EncodingFeature 似乎只是客户端库的一部分.每当请求通过接受编码建议编码时,我基本上都在寻找一种可能性,让泽西服务器将数据编码为 gzip.

The EncodingFeature seems to only be a part of the client library. I am basically looking for a possibility to make the Jersey server encode data as gzip whenever the request suggested the encoding via accept-encoding.

当我尝试在网络上搜索解决方案时,我发现了很多.他们中的大多数都关注 Jersey 1.其中一些建议向 GrizzlyServer 添加一个侦听器(这将是 Jersey 特定的而不是 JAX-RS?).然后在 Jersey 2 依赖树中有很多类建议使用 GZip 编码:

When I try to search for solutions on the web, I find plenty. Most of them concern Jersey 1. Some of them suggest adding a listener to the GrizzlyServer (which would be Jersey specific and not JAX-RS?). Then there are plenty classes within the Jersey 2 dependency tree that suggest GZip encoding:

org.glassfish.grizzly.http.GZipContentEncodingorg.glassfish.jersey.message.GZipEncoderorg.glassfish.grizzly.compression.zip.GZipEncoderorg.glassfish.grizzly.compression.zip.GZipDecoderorg.glassfish.grizzly.compression.zip.GZipFilter

我发现网络上的人建议使用其中任何一个,尽管我喜欢认为 org.glassfish.jersey 似乎是正确的选择,因为它是一个实际的 Jersey 依赖项.更不用说在 ApacheConnector 相关库中找到的那些了.我不知道我应该实际使用哪一个.

I found that people on the web suggest using any of them even though I like to think that org.glassfish.jersey seems to be the right choice since it is an actual Jersey dependency. Not to speak of those that are found in the ApacheConnector related libraries. I have no idea which one I should actually use.

推荐答案

我通过查看 Jersey 库找到了答案.对于服务器端,需要进行如下配置:

I figured it out by looking through the Jersey library. For the server side, the following configuration is necessary:

@Override
@SuppressWarnings("unchecked")
protected Application configure() {
    ResourceConfig resourceConfig = new ResourceConfig(MyResource.class);
    EncodingFilter.enableFor(resourceConfig, GZipEncoder.class);
    return resourceConfig;
}

在convers下,EncodingFilter#enableFor(ResourceConfig.Class