有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用HttpClient处理HTTP/2 GOAWAY?

我尝试每隔几分钟向RESTAPI连续发送GET和POST请求。问题是,在1000次请求之后,我收到一个^{}帧(和一个IOException):

The GOAWAY frame (type=0x7) is used to initiate shutdown of a connection or to signal serious error conditions.
HTTP/2 spec


我做了大量的研究,发现不仅1000个请求nginx's default maximum,Cloudfront(related Chromium issue)和Discord也表现出同样的行为

我试图用默认HTTP/2配置的本地nginx服务器重现此问题:

server {
    listen 443 http2 ssl;
    http2_max_requests 1000;
    ...
}
var client = HttpClient.newBuilder()
        .version(HttpClient.Version.HTTP_2)
        .build();

for (var i = 0; i < 1100; i++) {
    var url = URI.create(String.format("https://localhost/images/test%d.jpg", i));

    var request = HttpRequest.newBuilder().uri(url).build();

    client.send(request, HttpResponse.BodyHandlers.discarding());
    System.out.printf("Image %d processed%n", i);
}

在大约1000个请求之后,我得到了一个GOAWAY错误,正如预期的那样:

...
Image 998 processed
Exception in thread "main" java.io.IOException: /127.0.0.1:49259: GOAWAY received

我的第一个想法是检查异常消息是否包含字符串"GOAWAY",然后相应地重试请求:

try {
    client.send(request, HttpResponse.BodyHandlers.discarding());
} catch (IOException e) {
    if (e.getMessage().contains("GOAWAY")) {
        client.send(request, HttpResponse.BodyHandlers.discarding());
    } else throw e;
}

我对这种方法的问题是字符串比较似乎很脆弱。此外,由于我只有一个带有消息的IOException,所以我无法区分带有真实错误代码的GOAWAY帧(在这种情况下,我可能应该停止发送请求)和带有NO_ERROR的帧(在这种情况下,我可能会重试请求)

我应该如何正确处理/handleGOAWAY错误(除了使用HTTP/1.1之外)


共 (1) 个答案

  1. # 1 楼答案

    服务器有权出于任何原因随时关闭连接

    在HTTP/2 GOAWAY框架中,有服务器处理的最后一个流的指示,因此客户端可以知道在连接关闭时需要重新发送的流

    不幸的是,{}并没有出现在{}中,所以没有办法知道它并采取适当的行动

    您可以选择使用其他支持lastStreamId的客户机,或者使用较低级别的HTTP/2客户机,在那里可以使用GOAWAY帧,从而访问lastStreamId

    [免责声明,我是Jetty HTTP/2的实现者]
    Jetty支持一个较低级别的HTTP/2客户机,您可以将其用于您的用例——您可能想尝试一下。 你可以找到一个如何使用Jetty的HTTP2Clienthere的例子