当前位置: 首页 > 知识库问答 >
问题:

如何使用Apache HttpCient-5测试版正确执行Http2

慕烨烁
2023-03-14

您好,我正在尝试编写一个客户端,该客户端向多个服务器(已经支持http2)发出http2请求。到目前为止,我已经编写了这个独立的程序,它运行良好,我可以看到所有请求都通过相同的tcp连接(在wireshark的帮助下验证)。我使用Apache Httpclient 5和conscrypt来支持jdk8中的ALPN(我需要jdk8,我无法升级到jdk9或更高版本)

主街区就像,

try {
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager(){
            public X509Certificate[] getAcceptedIssuers(){ return null; }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {}
            public void checkServerTrusted(X509Certificate[] certs, String authType) {}
        }
    };
    Provider provider = Conscrypt.newProvider();
        
    SSLContext sslContext = SSLContext.getInstance("TLSv1.3", provider);
    sslContext.init(null, trustAllCerts, new SecureRandom());
        
    client = Http2AsyncClientBuilder.create().setTlsStrategy(new ConscryptClientTlsStrategy(sslContext)).setH2Config(H2Config.DEFAULT).build();
    client.start();
        
    ThreadPoolExecutor tpe = (ThreadPoolExecutor)Executors.newFixedThreadPool(50);
    for (int i=0; i < 50; i++) {
        Runnable worker = new WorkerClass(client, i);
        tpe.execute(worker);
    }
} catch (Exception e) {
    e.printStackTrace();
}

runnable是这样的,

static class WorkerClass implements Runnable {
    CloseableHttpAsyncClient client = null;
    int i = 0;
    WorkerClass(CloseableHttpAsyncClient client, int i) {
        this.client = client;
        this.i = i;
    }
    public void run() {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(Timeout.of(15, TimeUnit.SECONDS))//Determines the timeout until a new connection is fully established.
                .setConnectionRequestTimeout(Timeout.of(60, TimeUnit.SECONDS))//Returns the connection lease request timeout used when requesting a connection from the connection manager.
                .setResponseTimeout(Timeout.of(60, TimeUnit.SECONDS))//Determines the timeout until arrival of a response from the opposite endpoint.
                .build();
        
        String url = "https://localhost:8081/myagent/getOutput?"+System.currentTimeMillis();
        String cachedXMLRequest = "<?xml version=\"1.0\" standalone=\"no\"?><My XML REQUEST GOES HERE>";
        SimpleHttpRequest request= SimpleHttpRequests.POST.create(url);         
        request.setBodyText(cachedXMLRequest, ContentType.APPLICATION_JSON);
        request.setConfig(requestConfig);           
        final CountDownLatch latch = new CountDownLatch(1);         
        client.execute(request, new FutureCallback<SimpleHttpResponse>() {
            @Override
            public void cancelled() {
                System.out.println("Cancelled");
                latch.countDown();
            }

            @Override
            public void completed(SimpleHttpResponse arg0) {
                System.out.println("Completed "+arg0.getBodyText());
                latch.countDown();
            }

            @Override
            public void failed(Exception exception) {
                System.out.println("Failed ");
                exception.printStackTrace();
                latch.countDown();
            }
        });
        
        try {
            latch.await(60, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

因此,我在我的客户端中模拟了这个独立程序,该程序使用上述逻辑异步调用多个服务器进行轮询。但在这里,我可以看到每个请求有一个tcp连接,并且连接在请求结束时关闭(尽管响应头返回HTTP/2.0)。我使用主块代码在应用程序启动时初始化客户端(线程池部分除外,因为它用于独立模拟多线程环境),创建url、请求和响应对象,并在线程模型中同时执行每个请求(异步多路复用)。我的要求是每个域使用一个tcp连接,并将其用于长时间处理大量请求。我错过了什么?

或者有人告诉我使用httpClient 5处理http2的正确方法

有点让人明白了。

已编辑:

有两件事我追踪到异常连接关闭,

1.每次请求后连接都会关闭

原因:由此行引起

RequestConfig RequestConfig=RequestConfig。自定义()。setConnectTimeout(Timeout.of(15,TimeUnit.SECONDS))。。。

这个setConnectTimeout应该处于请求级别,但在15秒空闲后,它关闭了tcp连接本身,我不知道这是一个错误还是预期行为,因为根据文档,此配置用于封装请求项。

删除这一行可以使tcp连接在多个请求中保持活动状态。

2、由于非法标头帧/协议错误/内部错误

我可以在有线日志中看到这些异常,准确地说我的tcp连接正在关闭(它随机关闭),我无法共享整个日志,因为有太多我只是发布异常部分

0 x 0][0 x 1][0 x 0][0 x 0][0 x 4][0 xff ffffc 9]”

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08,666调试-i/o-0000001B

2019-02-07 16:05:08827调试-i/o-0000001B

2019-02-07 16:05:08827调试-i/o-0000001B

2019-02-07 16:05:08827调试-i/o-0000001B

2019-02-07 16:05:08827调试-i/o-0000001B

2019-02-07 16:05:08828调试-i/o-0000001B

2019-02-07 16:05:08828调试-i/o-0000001B

2019-02-07 16:05:08828调试-i/o-0000001B

2019-02-07 16:05:08828调试-i/o-0000001B

2019-02-07 16:05:08829调试-i/o-0000001B

2019-02-07 16:05:08829调试-i/o-0000001B

2019-02-07 16:05:08829调试-i/o-0000001B

2019-02-07 16:05:10,401DEBUG-ex-0000018D:准备请求执行

和,

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17,519调试-i/o-0000000C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

2019-02-07 16:17:17569调试-i/o-0000000 C

我不知道是什么原因导致了这些异常,我尝试了静态和动态post body数据,它们的行为都很相似

完整会话日志:

https://drive.google.com/open?id=12y8HnaMTrPo-NBeLaoCYpK6zklJBL56T

https://drive.google.com/open?id=16KHgqLWrwz3Z3ls3Yvpp58zOI3SUNATM

客户端:Tomcat 9.0x,Jdk 1.8。在ubuntu 16上的x(使用conscrypt支持ALPN,我们通过TLSv1.3连接它)。x

服务器:Tomcat 9.0x(带有openssl实现,NIO连接器,http2支持),openssl 1.1.1用于TLSv1.3支持,JDK 10.0.2在ubuntu 14上。x

任何帮助都将不胜感激

提亚

共有1个答案

解飞语
2023-03-14

案例1:服务器无序发送标题。

更新

情况2:服务器为空闲流发送RST\U流

这看起来像是Tomcat中的错误。这是一个连接的会话日志,为简洁起见,仅截取了DATA帧的内容

2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> stream 0 frame: SETTINGS (0x4); flags: (0x0); length: 36
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> HEADER_TABLE_SIZE: 8192
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> ENABLE_PUSH: 0
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> MAX_CONCURRENT_STREAMS: 100
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> INITIAL_WINDOW_SIZE: 65535
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> MAX_FRAME_SIZE: 65536
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> MAX_HEADER_LIST_SIZE: 16777215
2019-02-07 16:15:47,389 DEBUG - i/o-00000003 >> "[0x0][0x0]$[0x4][0x0][0x0][0x0][0x0][0x0][0x0][0x1][0x0][0x0] [0x0][0x0][0x2][0x0][0x0][0x0][0x0][0x0][0x3][0x0][0x0][0x0]d[0x0][0x4][0x0][0x0][0xffffffff][0xffffffff][0x0][0x5][0x0][0x1][0x0][0x0][0x0][0x6][0x0][0xffffffff][0xffffffff][0xffffffff]"
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << "[0x0][0x0][0x6][0x4][0x0][0x0][0x0][0x0][0x0][0x0][0x3][0x0][0x0][0x0][0xffffffc8][0x0][0x0][0x0][0x4][0x1][0x0][0x0][0x0][0x0][0x0][0x0][0x8][0x6][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x1]"
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << stream 0 frame: SETTINGS (0x4); flags: (0x0); length: 6
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << MAX_CONCURRENT_STREAMS: 200
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> stream 0 frame: SETTINGS (0x4); flags: ACK (0x1); length: 0
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> "[0x0][0x0][0x0][0x4][0x1][0x0][0x0][0x0][0x0]"
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << stream 0 frame: SETTINGS (0x4); flags: ACK (0x1); length: 0
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << stream 0 frame: PING (0x6); flags: (0x0); length: 8
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 << ........          00 00 00 00 00 00 00 01
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> stream 0 frame: PING (0x6); flags: ACK (0x1); length: 8
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> ........          00 00 00 00 00 00 00 01
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> "[0x0][0x0][0x8][0x6][0x1][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x1]"
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> :method: POST
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> :scheme: https
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> :authority: 172.21.170.214:8999
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> :path: /monitoragent/getdcoutput?1000000004286_1520339351002_1549536347382
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> user-agent: Apache-HttpAsyncClient/5.0-beta3 (Java/1.8.0_162)
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> content-type: application/json; charset=UTF-8
2019-02-07 16:15:47,393 DEBUG - i/o-00000003 >> stream 1 frame: HEADERS (0x1); flags: END_HEADERS (0x4); length: 130
...
2019-02-07 16:15:47,394 DEBUG - i/o-00000003 >> stream 1 frame: DATA (0x0); flags: (0x0); length: 1208
...
2019-02-07 16:15:47,394 DEBUG - i/o-00000003 >> stream 0 flow control -1208 -> 64327
2019-02-07 16:15:47,394 DEBUG - i/o-00000003 >> stream 1 flow control -1208 -> 64327
...
2019-02-07 16:15:47,394 DEBUG - i/o-00000003 >> stream 1 frame: DATA (0x0); flags: END_STREAM (0x1); length: 0
2019-02-07 16:15:47,394 DEBUG - i/o-00000003 >> "[0x0][0x0][0x0][0x0][0x1][0x0][0x0][0x0][0x1]"
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> :method: POST
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> :scheme: https
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> :authority: 172.21.170.214:8999
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> :path: /monitoragent/getdcoutput?1000000004286_1520339351002_1549536347382
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> user-agent: Apache-HttpAsyncClient/5.0-beta3 (Java/1.8.0_162)
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> content-type: application/json; charset=UTF-8
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> stream 3 frame: HEADERS (0x1); flags: END_HEADERS (0x4); length: 6
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> ......            83 87 c1 c0 bf be
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> "[0x0][0x0][0x6][0x1][0x4][0x0][0x0][0x0][0x3][0xffffff83][0xffffff87][0xffffffc1][0xffffffc0][0xffffffbf][0xffffffbe]"
...
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> stream 0 flow control -1208 -> 63119
2019-02-07 16:15:47,395 DEBUG - i/o-00000003 >> stream 3 flow control -1208 -> 64327
...
2019-02-07 16:15:47,396 DEBUG - i/o-00000003 >> stream 3 frame: DATA (0x0); flags: END_STREAM (0x1); length: 0
2019-02-07 16:15:47,396 DEBUG - i/o-00000003 >> "[0x0][0x0][0x0][0x0][0x1][0x0][0x0][0x0][0x3]"
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << "[0x0][0x0][0x4][0x8][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x4][0xffffffb8][0x0][0x0][0x4][0x8][0x0][0x0][0x0][0x0][0x3][0x0][0x0][0x4][0xffffffb8]"
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << stream 0 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << Increment 1208
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 >> stream 0 flow control 1208 -> 64327
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << stream 3 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << Increment 1208
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 >> stream 3 flow control 1208 -> 65535
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << "[0x0][0x0][0x4][0x8][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x4][0xffffffb8][0x0][0x0][0x4][0x8][0x0][0x0][0x0][0x0][0x1][0x0][0x0][0x4][0xffffffb8]"
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << stream 0 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << Increment 1208
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 >> stream 0 flow control 1208 -> 65535
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << stream 1 frame: WINDOW_UPDATE (0x8); flags: (0x0); length: 4
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 << Increment 1208
2019-02-07 16:15:47,399 DEBUG - i/o-00000003 >> stream 1 flow control 1208 -> 65535
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 << "[0x0][0x0][0x4][0x3][0x0][0x0][0x0][0x0]3[0x0][0x0][0x0][0x2]"
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 << stream 51 frame: RST_STREAM (0x3); flags: (0x0); length: 4
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 << Code INTERNAL_ERROR
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 >> stream 0 frame: GOAWAY (0x7); flags: (0x0); length: 32
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 >> Last stream 0
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 >> Code PROTOCOL_ERROR
2019-02-07 16:15:47,503 DEBUG - i/o-00000003 >> Unexpected stream id: 51
2019-02-07 16:15:47,504 DEBUG - i/o-00000003 >> "[0x0][0x0] [0x7][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x0][0x1]Unexpected stream id: 51"  

在消息交换结束时,服务器为流51发送RST_STREAM。没有流51。有流1和3,它们都已正确关闭。然后,无论出于什么原因,服务器决定终止空闲流51。根据RFC 7540,第6.4节,客户端将此类操作视为严重的协议违规

RST_STREAM frames MUST NOT be sent for a stream in the "idle" state.
If a RST_STREAM frame identifying an idle stream is received, the
recipient MUST treat this as a connection error (Section 5.4.1) of
type PROTOCOL_ERROR.

请升级到最新版本的Tomcat 9,如果问题仍然存在,请向Tomcat开发人员报告。

 类似资料:
  • 问题内容: 我在NetBeans 8.2中的一个新的干净Maven项目中创建了此测试: 如果我运行测试,日志显示 我的pom.xml包含以下依赖项: 是什么导致JUnit 5忽略测试方法? 更新:我添加了surefire插件,这是完整的pom.xml: 输出更改为: 并且surefire-reports文件夹包含两个“ .dump”文件。第一个内容: 问题答案: 确保将您的配置正确地设置为: 而且

  • 我有一个函数,在这个函数中,我想替换一些组件的行为(余弦,正弦,...),我正在尝试为这些部分创建一个mock,并将它们传递给函数。 问题是,我收到以下消息: *org.mockito.exceptions.misusing.MissingMethodInvocationException:当()需要一个必须是“模拟上的方法调用”的参数。例如:当(mock.getArticles()). then

  • 我正在尝试使用测试驱动设计方法编写一个应用程序--我对单元测试很陌生,所以我只是想知道测试正确输入和异常的正确方法是什么。 我有一个用于加载配置文件的类: null 另外,这3个测试是否都有try{}catch(){}语句?在第一个测试中,正确性是隐含的,在第二个和第三个测试中,我无论如何都在检查异常,所以异常对测试没有影响。

  • 如何正确执行collect以获取作为键并将Ethernet对象作为每个流元素的值?

  • 我正在尝试处理如何使用try-catch。我知道它将“尝试”主代码,如果它不工作,它将捕获它并执行不同的操作。我还希望不断提示用户输入正确的值。 我一直得到输入不匹配异常错误,即使我设置我的捕获在其块中。 澄清一下:当我向用户询问他们计划停留多长时间,以及他们希望呆在哪一层楼的INT时,try-catch就会出现。因此,我想处理的错误包括非整数,以及它们是否超出“hotel”的范围。 这是我的密码

  • 我试图保存文件到文件系统使用文件上传功能。因为angular应用程序需要这个文件,而不是后端(rest API-Java),所以我决定将它保存在前端应用程序中,这意味着angular应用程序的资产文件夹中的某个位置。 你知道如何把文件保存在文件夹里吗?谢了。