为什么Jersey会吞下我的"Content-Encoding"标题

Raf*_*ter 5 jax-rs jersey jersey-client

为什么以下示例在请求中吞下我的HTTP-Header以进行"Content-Encoding".我正在编写一个应用程序,我需要解码自定义编码格式.但是,我永远无法从请求中获取"Content-Encoding"标头.既不在实际资源中也不在ReaderInterceptor中.在响应中,不吞下此编码头.

在以下(可运行)示例中可以很容易地观察到此行为:

public class Demo extends JerseyTest {
  @Override
  protected Application configure() {
    enable(TestProperties.DUMP_ENTITY);
    enable(TestProperties.LOG_TRAFFIC);
    return new ResourceConfig(MyResource.class, MyInterceptor.class);
  }

  public static final String PATH = "path";
  public static final String ENCODING = "my-encoding";
  public static final String CUSTOM_HEADER = "X-Content-Encoding";
  public static final String QUESTION = "question", ANSWER = "answer";

  @Path(PATH)
  public static class MyResource {
    @POST
    public Response handle(String value, @Context HttpHeaders httpHeaders) {
      assertEquals(ENCODING, httpHeaders.getHeaderString(CUSTOM_HEADER));
      // Here, the "Content-Encoding" header mysteriously disappeared.
      assertEquals(ENCODING, httpHeaders.getHeaderString(HttpHeaders.CONTENT_ENCODING));
      return Response
          .ok(ANSWER)
          .header(CUSTOM_HEADER, ENCODING)
          .header(HttpHeaders.CONTENT_ENCODING, ENCODING)
          .build();
    }
  }

  public static class MyInterceptor implements ReaderInterceptor, WriterInterceptor {
    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) 
        throws IOException, WebApplicationException {
      assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
      // Here, the "Content-Encoding" header mysteriously disappeared.
      assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
      return context.proceed();
    }

    @Override
    public void aroundWriteTo(WriterInterceptorContext context) 
        throws IOException, WebApplicationException {
      assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
      // Here, the "Content-Encoding" header can be found.
      assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
      context.proceed();
    }
  }

  @Test
  public void test() throws Exception {
    Response response = target(PATH)
        .request()
        .header(CUSTOM_HEADER, ENCODING)
        .header(HttpHeaders.CONTENT_ENCODING, ENCODING)
        .post(Entity.text(QUESTION));
    assertEquals(200, response.getStatus());
    assertEquals(ENCODING, response.getHeaders().getFirst(CUSTOM_HEADER));
    // Here, the "Content-Encoding" header can be found.
    assertEquals(ENCODING, response.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
  }
}
Run Code Online (Sandbox Code Playgroud)

在泽西试图修复我的内容编码的窗帘后面是否有一些神奇的事情发生?(它不能,因为它是一个闭源编码,我必须通过在网络中的另一台服务器上查询另一个应用程序来解决.)我甚至无法在请求转储中发现"Content-Encoding"标头这就是为什么我怀疑泽西岛根本不发送标题.

我当然可以使用一些"X-Content-Encoding"标头,这可以在示例中演示.但这个解决方案只是愚蠢.我已经找遍了各种CommonProperties,ServerProperties,ClientProperties常量池,但我没有找到一个配置选项.

小智 7

您看到的问题是因为您实际上用.覆盖了Content-Encoding标头

.post(Entity.text(QUESTION));
Run Code Online (Sandbox Code Playgroud)

呼叫.该Entity.text(...)方法生成实体,其内容数据Variant字段设置为:

media type = "text/plain";
content language = null;
content encoding = null;
Run Code Online (Sandbox Code Playgroud)

这些null内容编码和语言的值依次擦除任何先前的集合Content-EncodingContent-Language标题.要解决此问题,您需要将内容编码指定为实体的一部分:

    Response response = target(PATH)
            .request()
            .post(Entity.entity(QUESTION, 
                  new Variant(MediaType.TEXT_PLAIN_TYPE, (String) null, "my-encoding")));
Run Code Online (Sandbox Code Playgroud)

(我同意这种行为有点令人困惑,因为它并不明显.也许我们应该修复Jersey,null如果设置了,则不要使用变量字段值覆盖标题...)