Как обрабатывать HTTP / 2 GOAWAY с HttpClient? - PullRequest
2 голосов
/ 10 марта 2019

Я пытаюсь непрерывно отправлять запросы GET и POST API REST каждые несколько минут. Проблема в том, что после ровно 1000 запросов я получаю кадр GOAWAYIOException):

Кадр GOAWAY (тип = 0x7) используется для инициирования отключения соединения или сигнализации о серьезных ошибках.
HTTP / 2 spec


Я провел немало исследований и обнаружил, что не только 1000 запросов максимальное значение по умолчанию nginx , Cloudfront ( связанная с Chromium проблема ) и Discord также демонстрируют аналогичное поведение.

Я попытался воспроизвести эту проблему на локальном сервере nginx с конфигурацией HTTP / 2 по умолчанию:

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
<b>Exception in thread "main" java.io.IOException: /127.0.0.1:49259: GOAWAY received</b>

Моей первой мыслью было бы проверить, содержит ли сообщение об исключении строку "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 (в этом случае я возможно, можно повторить запрос).

Как правильно обрабатывать / обрабатывать GOAWAY ошибок (не считая использования HTTP / 1.1)?

1 Ответ

1 голос
/ 10 марта 2019

Сервер имеет право закрывать соединения в любое время и по любой причине.

В кадре HTTP / 2 GOAWAY указывается, какой последний поток был обработан сервером, поэтомуклиент может знать, какой поток необходимо повторно отправить, когда соединение закрыто.

К сожалению, lastStreamId не отображается в java.net.http.HttpClient, поэтому нет способа узнать его и предпринять соответствующие действия.

В качестве альтернативы вы можете использовать других клиентов, которые поддерживают всплывающее окно lastStreamId, или использовать HTTP / 2-клиент более низкого уровня, где у вас будет доступен фрейм GOAWAY и, следовательно, доступ к lastStreamId.

[Отказ от ответственности, я являюсь разработчиком Jetty HTTP / 2]
Jetty поддерживает HTTP / 2-клиент более низкого уровня, который вы можете использовать для своего случая использования - вы можете попробовать.Вы можете найти пример использования Jetty's HTTP2Client здесь .

...