Тайм-аут Java HttpRequest неожиданно выбрасывает HttpConnectTimeoutException

Используя новый java.net.http пакет выпущен с JDK 11, HttpRequest был собран с намеренно низким временем ожидания ответа:

HttpRequest.Builder builder = HttpRequest.newBuilder(getEndpointUri());
addRequestHeaders(builder);
builder.POST(HttpRequest.BodyPublishers.ofString(rawXml));
builder.timeout(Duration.ofMillis(1));
HttpRequest httpRequest = builder.build();

Цель состоит в том, чтобы проверить, что HttpTimeoutException результаты обрабатываются правильно, но неожиданно это значение времени ожидания ответа приводит к HttpConnectionTimeoutException, который ловится этим кодом:

try {
    HttpResponse<InputStream> httpResponse = completableExchange.join();
} catch (CompletionException ce) {
    if (ce.getCause() instanceof HttpConnectTimeoutException) {
        System.out.println("Connection timeout occurred!");
    } else {
        throw ce;
    }
}

Это означает, что тайм-аут ответа заставляет код действовать так, как если бы тайм-аут соединения произошел. Насколько я понимаю, время ожидания соединения и время ответа должны быть отдельными понятиями, которые должны быть в состоянии уловить и обработать отдельно.

Трассировка стека, прикрепленная к HttpConnectionTimeoutException выглядит так:

java.net.http.HttpConnectTimeoutException: HTTP connect timed out
    at java.net.http/jdk.internal.net.http.ResponseTimerEvent.handle(ResponseTimerEvent.java:68)
    at java.net.http/jdk.internal.net.http.HttpClientImpl.purgeTimeoutsAndReturnNextDeadline(HttpClientImpl.java:1248)
    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:877)
Caused by: java.net.ConnectException: HTTP connect timed out
    at java.net.http/jdk.internal.net.http.ResponseTimerEvent.handle(ResponseTimerEvent.java:69)
    ... 2 more

Я неправильно понимаю концепции тайм-аута? Ли HttpRequest Значение тайм-аута просто предоставить альтернативу по умолчанию HttpClient значение тайм-аута? Есть ли надежный способ отловить время ожидания соединения и ответа как отдельные события?

Для чего это стоит, Javadoc для HttpRequest.Builder.timeout(Duration) говорит следующее:

Устанавливает время ожидания для этого запроса. Если ответ не получен в течение указанного времени ожидания, HttpTimeoutException генерируется из HttpClient::send или HttpClient::sendAsync, который завершается исключительно с HttpTimeoutException. Эффект не установки тайм-аута такой же, как и установка бесконечной длительности, т.е. заблокировать навсегда.

Чтобы запутать вещи, HttpConnectionTimeoutException это подкласс HttpTimeoutException так технически контракт timeout(Duration) метод удовлетворяется. Но это кажется бесполезным.

(Прежде чем спросить: да, значение передается HttpRequest.Builder.timeout(Duration) является решающим фактором, будет ли выброшено исключение. Таким образом, исключение не основано на значении тайм-аута соединения, используемого для создания HttpClient пример.)

1 ответ

IIRC вы получите HttpConnectionTimeoutException, если соединение не будет подключено в момент истечения времени ожидания или если время соединения увеличено до завершения соединения.

При отправке запроса - базовое соединение может быть уже подключено или нет - в зависимости от того, было ли найдено подходящее существующее соединение в пуле. Время ожидания запроса начинается немедленно - независимо от состояния базового соединения. Если базовое соединение еще не подключено и время ожидания запроса истекает до его подключения, вы получите исключение HttpConnectionTimeoutException, поскольку соединение не может быть установлено в течение времени, выделенного для ответа на запрос, подлежащий доставке. Вы могли видеть это как тайм-аут запроса, ограничивающий тайм-аут соединения.

Есть ли у вас какие-либо конкретные варианты использования для различения двух вариантов:

  1. HttpConnectionTimeoutException вызывается, потому что соединение не может быть установлено в течение времени, указанного в тайм-ауте соединения,
  2. HttpConnectionTimeoutException повышен, потому что истекло время ожидания запроса прежде, чем соединение могло быть соединено?
Другие вопросы по тегам