Боюсь, это невозможно в клиентском API http Java 11.
Наиболее подходящим внутренним классом JDK является Http2Connection.java. В нем перечислены три случая «создания», которые мы ожидаем для соединений HTTP/2:
- обновленное HTTP/1.1 простое TCP-соединение
- предварительное знание напрямую создало простое TCP-соединение
- непосредственно созданное HTTP/2 SSL-соединение, которое использует ALPN.
Нас интересует случай 2. Для этого есть код:
/**
* Cases 2) 3)
*
* request is request to be sent.
*/
private Http2Connection(HttpRequestImpl request,
Http2ClientImpl h2client,
HttpConnection connection)
throws IOException
{
...
}
Увы, этот конструктор фактически используется только из метода для безопасных соединений:
// Requires TLS handshake. So, is really async
static CompletableFuture<Http2Connection> createAsync(HttpRequestImpl request,
Http2ClientImpl h2client,
Exchange<?> exchange) {
assert request.secure();
AbstractAsyncSSLConnection connection = (AbstractAsyncSSLConnection)
...
return connection.connectAsync(exchange)
.thenCompose(unused -> connection.finishConnect())
.thenCompose(unused -> checkSSLConfig(connection))
.thenCompose(notused-> {
CompletableFuture<Http2Connection> cf = new MinimalFuture<>();
try {
Http2Connection hc = new Http2Connection(request, h2client, connection);
cf.complete(hc);
} catch (IOException e) {
cf.completeExceptionally(e);
}
return cf; } );
Конструкторы, отличные от TLS, вызываются только при обновлении соединения HTTP 1.1.
Я изучил и многие другие классы. Я не вижу ничего, что могло бы предположить, что соединения HTTP/2 с открытым текстом можно согласовать без обновления с HTTP 1.1 в клиенте JDK 11.
То, что я нашел, очень совпадает с описанием API в javadocs для HttpClient.Builder, в котором говорится только о выборе HTTP/2 в качестве версии:
Если установлено значение HTTP/2, каждый запрос будет пытаться обновиться до HTTP/2. Если обновление пройдет успешно, ответ на этот запрос будет использовать HTTP/2, а все последующие запросы и ответы на тот же исходный сервер будут использовать HTTP/2. Если обновление не удалось, ответ будет обработан с использованием HTTP/1.1.
В повторном использовании соединения HTTP/2 происходит много интересного. Например, когда одновременные запросы обновляются, только один сохраняется для будущего использования в «кэше» соединения HTTP/2. Кэшированное соединение истечет, когда количество потоков достигнет максимума, который составляет ~ 2^31-1, так что дальнейшие запросы не превысят его, но существующие потоки останутся открытыми. Это много потоков. Я думаю, что если ваш вариант использования подобен моему — клиент веб-службы в очень долго работающих приложениях — тогда стоимость обновления практически только по первому запросу незначительна. Я все еще хотел бы исключить его, в основном для простоты, но я начинаю думать, что это того не стоит.
Как и спрашивающий, я хотел бы придерживаться клиента JDK. Я просто упомяну, что бета-версия Apache HttpClient 5 поддерживает форсирование HTTP/2 (HttpVersionPolicy.FORCE_HTTP_2). Я не могу ничего посоветовать по этому поводу, потому что в бета-версии не так много документации, а комментарии гораздо реже, чем в реализации JDK. Но если я попробую и добьюсь успеха, я обновлю свой ответ.
person
drrob
schedule
19.03.2019