HTTP2 url在浏览器中成功加载但在httpclient5中失败

时间:2018-02-19 06:45:25

标签: java tomcat http2 apache-httpasyncclient apache-httpclient-5.x

我正在尝试使用as example创建一个使用asynchttpclient(异步多路复用)加载URL的httpclient 5示例,我已使用conf / server.xml配置将tomcat 9配置为接受http2协议,如下所示

<Connector
       protocol="org.apache.coyote.http11.Http11NioProtocol"
       port="8443" maxThreads="200"
       scheme="https" secure="true" SSLEnabled="true"
       keystoreFile="conf/xxx.keystore" keystorePass="xxx#"
       clientAuth="false" sslProtocol="TLS"><UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/></Connector>

和我的程序如下,

    final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustAllStrategy()).build();
    final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create().setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setSoTimeout(Timeout.ofSeconds(5)).build();
    final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig, connectionManager);


    client.start();

    final HttpHost target = new HttpHost("localhost", 8084, "https");
    System.out.println(target.getPort());
    final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
    final AsyncClientEndpoint endpoint = leaseFuture.get(45, TimeUnit.SECONDS);
    try {
        final String[] requestUris = new String[] {"/index.html"};

        final CountDownLatch latch = new CountDownLatch(requestUris.length);
        for (final String requestUri: requestUris) {
            final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);

            endpoint.execute(SimpleRequestProducer.create(request), SimpleResponseConsumer.create(), new FutureCallback<SimpleHttpResponse>() {
                        @Override
                        public void completed(final SimpleHttpResponse response) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + response.getCode());
                            System.out.println(response.getBody());
                        }

                        @Override
                        public void failed(final Exception ex) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + ex);
                            ex.printStackTrace();
                        }

                        @Override
                        public void cancelled() {
                            latch.countDown();
                            System.out.println(requestUri + " cancelled");
                        }

                    });
        }
        latch.await();
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        endpoint.releaseAndReuse();
    }

    client.shutdown(ShutdownType.GRACEFUL);

tomcat配置在使用h2协议在borwser中加载页面时起作用,但是在httpclient 5失败时出现以下异常

/index.html->org.apache.hc.core5.http.ConnectionClosedException: Connection closed
org.apache.hc.core5.http.ConnectionClosedException: Connection closed
    at org.apache.hc.core5.http2.impl.nio.FrameInputBuffer.read(FrameInputBuffer.java:146)
    at org.apache.hc.core5.http2.impl.nio.AbstractHttp2StreamMultiplexer.onInput(AbstractHttp2StreamMultiplexer.java:415)
    at org.apache.hc.core5.http2.impl.nio.AbstractHttp2IOEventHandler.inputReady(AbstractHttp2IOEventHandler.java:63)
    at org.apache.hc.core5.http2.impl.nio.ClientHttp2IOEventHandler.inputReady(ClientHttp2IOEventHandler.java:38)
    at org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:117)
    at org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50)
    at org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173)
    at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123)
    at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80)
    at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)
    at java.lang.Thread.run(Thread.java:748)

对此的任何帮助将不胜感激

提前致谢

在启用tomcat日志时,我可以看到以下内容,

  

org.apache.coyote.AbstractProtocol $ ConnectionHandler.process失败   为协商协议创建处理器[h2c]

当我将客户端代码更新为java 9时,甚至会解决此问题,但是可以使其适用于java 8。

p.s:我知道java 8不支持ALPN,但请告诉我是否可以使用java 8。

2 个答案:

答案 0 :(得分:0)

我遇到了类似的问题,发现这是由于请求协议被用作https。由于我已经为客户设置了TLS策略,因此将协议更改为简单的&#39; http&#39;解决了这个问题。 替换线: final HttpHost target = new HttpHost(&#34; localhost&#34;,8084,&#34; https&#34;); 通过  final HttpHost target = new HttpHost(&#34; localhost&#34;,8084,&#34; http&#34;);

答案 1 :(得分:0)

通过使用conscrypt作为默认提供程序并使用自定义TLSStrategy,我们可以使其与jdk1.8一起使用,请参见

https://stackoverflow.com/a/53399363/2236001