ApacheConnector不处理在WriterInterceptor中设置的请求标头 [英] ApacheConnector does not process request headers that were set in a WriterInterceptor

查看:115
本文介绍了ApacheConnector不处理在WriterInterceptor中设置的请求标头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ApacheConnector配置球衣Client时遇到问题.似乎忽略了我在WriterInterceptor中定义的所有请求标头.我可以确定在WriterInterceptor#aroundWriteTo(WriterInterceptorContext)中设置断点时调用了WriterInterceptor.与此相反,我可以看到保留了InputStream的修改.

I am experiencing problems when configurating my Jersey Client with the ApacheConnector. It seems to ignore all request headers that I define in a WriterInterceptor. I can tell that the WriterInterceptor is called when I set a break point within WriterInterceptor#aroundWriteTo(WriterInterceptorContext). Contrary to that, I can observe that the modification of an InputStream is preserved.

这是一个可运行的示例,展示了我的问题:

Here is a runnable example demonstrating my problem:

public class ApacheConnectorProblemDemonstration extends JerseyTest {

  private static final Logger LOGGER = Logger.getLogger(JerseyTest.class.getName());
  private static final String QUESTION = "baz", ANSWER = "qux";
  private static final String REQUEST_HEADER_NAME_CLIENT = "foo-cl", REQUEST_HEADER_VALUE_CLIENT = "bar-cl";
  private static final String REQUEST_HEADER_NAME_INTERCEPTOR = "foo-ic", REQUEST_HEADER_VALUE_INTERCEPTOR = "bar-ic";
  private static final int MAX_CONNECTIONS = 100;
  private static final String PATH = "/";

  @Path(PATH)
  public static class TestResource {
    @POST
    public String handle(InputStream questionStream,
                         @HeaderParam(REQUEST_HEADER_NAME_CLIENT) String client,
                         @HeaderParam(REQUEST_HEADER_NAME_INTERCEPTOR) String interceptor) 
        throws IOException {
      assertEquals(REQUEST_HEADER_VALUE_CLIENT, client);
      // Here, the header that was set in the client's writer interceptor is lost.
      assertEquals(REQUEST_HEADER_VALUE_INTERCEPTOR, interceptor);
      // However, the input stream got gzipped so the WriterInterceptor has been partly applied.
      assertEquals(QUESTION, new Scanner(new GZIPInputStream(questionStream)).nextLine());
      return ANSWER;
    }
  }

  @Provider
  @Priority(Priorities.ENTITY_CODER)
  public static class ClientInterceptor implements WriterInterceptor {
    @Override
    public void aroundWriteTo(WriterInterceptorContext context) 
        throws IOException, WebApplicationException {
      context.getHeaders().add(REQUEST_HEADER_NAME_INTERCEPTOR, REQUEST_HEADER_VALUE_INTERCEPTOR);
      context.setOutputStream(new GZIPOutputStream(context.getOutputStream()));
      context.proceed();
    }
  }

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

  @Override
  protected Client getClient(TestContainer tc, ApplicationHandler applicationHandler) {
    ClientConfig clientConfig = tc.getClientConfig() == null ? new ClientConfig() : tc.getClientConfig();
    clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, makeConnectionManager(MAX_CONNECTIONS));
    clientConfig.register(ClientInterceptor.class);
    // If I do not use the Apache connector, I avoid this problem.
    clientConfig.connector(new ApacheConnector(clientConfig));
    if (isEnabled(TestProperties.LOG_TRAFFIC)) {
      clientConfig.register(new LoggingFilter(LOGGER, isEnabled(TestProperties.DUMP_ENTITY)));
    }
    configureClient(clientConfig);
    return ClientBuilder.newClient(clientConfig);
  }

  private static ClientConnectionManager makeConnectionManager(int maxConnections) {
    PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
    connectionManager.setMaxTotal(maxConnections);
    connectionManager.setDefaultMaxPerRoute(maxConnections);
    return connectionManager;
  }

  @Test
  public void testInterceptors() throws Exception {
    Response response = target(PATH)
        .request()
        .header(REQUEST_HEADER_NAME_CLIENT, REQUEST_HEADER_VALUE_CLIENT)
        .post(Entity.text(QUESTION));
    assertEquals(200, response.getStatus());
    assertEquals(ANSWER, response.readEntity(String.class));
  }
}

我想使用ApacheConnector以便通过PoolingClientConnectionManager优化并发请求.我搞砸了配置吗?

I want to use the ApacheConnector in order to optimize for concurrent requests via the PoolingClientConnectionManager. Did I mess up the configuration?

PS:使用GrizzlyConnector时,会出现完全相同的问题.

PS: The exact same problem occurs when using the GrizzlyConnector.

推荐答案

经过进一步的研究,我认为这在使用HttpURLConnection的默认Connector中相当不当.正如我在其他自我我的文档说明 :

After further research, I assume that this is rather a misbehavior in the default Connector that uses a HttpURLConnection. As I explained in this other self-answered question of mine, the documentation states:

过滤器主要用于处理请求和 响应参数,例如HTTP标头,URI和/或HTTP方法, 拦截器旨在通过操纵来操纵实体 实体输入/输出流

Whereas filters are primarily intended to manipulate request and response parameters like HTTP headers, URIs and/or HTTP methods, interceptors are intended to manipulate entities, via manipulating entity input/output streams

不应使用WriterInterceptor来处理标头值,而不能使用{Client,Server}RequestFilter来操纵实体流.如果需要同时使用这两个组件,则应将这两个组件捆绑在javax.ws.rs.core.Feature中或实现两个接口的同一类中. (但是,如果您需要设置两个不同的Priority,则可能会出现问题.)

A WriterInterceptor is not supposed to manipulate the header values while a {Client,Server}RequestFilter is not supposed to manipulate the entity stream. If you need to use both, both components should be bundled within a javax.ws.rs.core.Feature or within the same class that implements two interfaces. (This can be problematic if you need to set two different Prioritys though.)

但是,所有这些都非常不幸,因为JerseyTest使用了使用HttpURLConnectionConnector,这样我的所有单元测试都成功了,而现实生活中的应用程序由于配置了ApacheConnector而表现不佳.另外,我希望泽西岛不要压抑变化,而是会给我一些例外. (这是我在Jersey遇到的一个普遍问题.例如,当我使用太新版本时,接口被重命名为HttpClientConnectionManager时,我只是在一行日志中被告知声明我的所有配置工作都被忽略了.直到开发很晚我才发现此日志语句.)

All this is very unfortunate though, since JerseyTest uses the Connector that uses a HttpURLConnection such that all my unit tests succeeded while the real life application misbehaved since it was configured with an ApacheConnector. Also, rather than suppressing changes, I wished, Jersey would throw me some exceptions. (This is a general issue I have with Jersey. When I for example used a too new version of the ClientConnectionManager where the interface was renamed to HttpClientConnectionManager I simply was informed in a one line log statement that all my configuration efforts were ignored. I did not discover this log statement til very late in development.)

这篇关于ApacheConnector不处理在WriterInterceptor中设置的请求标头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆