Тайм-аут 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, поскольку соединение не может быть установлено в течение времени, выделенного для ответа на запрос, подлежащий доставке. Вы могли видеть это как тайм-аут запроса, ограничивающий тайм-аут соединения.
Есть ли у вас какие-либо конкретные варианты использования для различения двух вариантов:
- HttpConnectionTimeoutException вызывается, потому что соединение не может быть установлено в течение времени, указанного в тайм-ауте соединения,
- HttpConnectionTimeoutException повышен, потому что истекло время ожидания запроса прежде, чем соединение могло быть соединено?