在使用Client
配置泽西ApacheConnector
时,我遇到了问题。它似乎忽略了我在WriterInterceptor
中定义的所有请求标头。我可以告诉我在WriterInterceptor
内设置断点时会调用WriterInterceptor#aroundWriteTo(WriterInterceptorContext)
。与此相反,我可以观察到InputStream
的修改被保留。
这是一个展示我问题的可运行示例:
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
的并发请求。我搞砸了配置吗?
PS:使用GrizzlyConnector
时会出现完全相同的问题。
答案 0 :(得分:3)
经过进一步研究,我认为这是使用Connector
的默认HttpURLConnection
中的错误行为。正如我在other self-answered question中所解释的那样documentation states:
而过滤器主要用于操纵请求和 响应参数,如HTTP头,URI和/或HTTP方法, 拦截器旨在通过操纵来操纵实体 实体输入/输出流
WriterInterceptor
不应该操纵标题值,而{Client,Server}RequestFilter
不应该操纵实体流。如果您需要同时使用这两个组件,则两个组件应捆绑在javax.ws.rs.core.Feature
内或在实现两个接口的同一个类中。 (如果你需要设置两个不同的Priority
,这可能会有问题。)
所有这一切都非常不幸,因为JerseyTest
使用了使用Connector
的{{1}},以便我的所有单元测试成功,而现实生活中的应用程序由于配置了HttpURLConnection
。而且,我希望泽西岛能给我一些例外,而不是压制变化。 (这是我与泽西岛的一般性问题。例如,当我使用太新版本的ApacheConnector
时,界面被重命名为ClientConnectionManager
我只是被告知一行日志语句,我的所有配置工作都被忽略。我没有发现这个日志语句直到开发很晚。)