我正在尝试每隔几分钟向 REST API 连续发送 GET 和 POST 请求。问题是在恰好 1000 个请求之后我收到一个 GOAWAY
框架(和 IOException
):
The GOAWAY frame (type=0x7) is used to initiate shutdown of a connection or to signal serious error conditions.
§ 6.8, RFC 7540
我做了一些研究,发现不仅有 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
My first thought would be to check if the exception message contains the string "GOAWAY"
and then retry the request accordingly:
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
(在这种情况下我可能会重试请求)。
我应该如何正确处理/处理 GOAWAY
错误(除了改用 HTTP/1.1 之外)?
最佳答案
服务器有权出于任何原因随时关闭连接。
在 HTTP/2 GOAWAY
框架中,指示服务器处理的最后一个流是什么,因此客户端可以知道在连接关闭时需要重新发送什么流。
不幸的是,lastStreamId
未出现在 java.net.http.HttpClient
中,因此无法了解它并采取适当的措施。
您的替代方案可能是使用其他支持显示 lastStreamId
的客户端,或者使用较低级别的 HTTP/2 客户端,您将在其中使用 GOAWAY
框架,因此访问 lastStreamId
。
[免责声明,我是 Jetty HTTP/2 实现者]
Jetty 支持较低级别的 HTTP/2 客户端,您可以将其用于您的用例——您可能想尝试一下。
您可以找到如何使用 Jetty 的 HTTP2Client
的示例 here .
关于java - 如何使用 HttpClient 处理 HTTP/2 GOAWAY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55087292/