1. Введение
Потоковая группа IETF одобрила протокол HTTP / 2 в 2015 году, через шестнадцать лет после выпуска HTTP / 1.1. HTTP / 2 обещает снизить задержку и делает многие из тех обходных путей устаревшими, которые были необходимы для HTTP / 1.1, чтобы соответствовать современным требованиям времени отклика. В этой статье я кратко расскажу о HTTP / 2 и о том, как он обновляет текстовый HTTP / 1.1, а затем мы рассмотрим будущую поддержку HTTP / 2 в Java 9.
2. Методы оптимизации задержки для HTTP / 1.1
Люди становятся все более и более стационарными в Интернете, но они не заметят, что действия, которые они выполняют в Интернете, не выполняются сами по себе, если время ответа меньше 100 мс.
Когда время отклика увеличивается до 1 с, что замечается, и когда сайт отвечает дольше 10 с, он считается неработоспособным. Согласно некоторым исследованиям, средняя продолжительность внимания снизилась до 7-8 секунд, и даже задержка в 1 секунду может привести к потере дохода на 7%.
Для HTTP / 1.1 требовались (иногда тяжелые) обходные пути для удовлетворения сегодняшних требований.
- Поскольку одно HTTP-соединение может загружать по одному ресурсу за раз, браузеры извлекают их одновременно, чтобы быстрее отображать страницу. Однако число параллельных подключений на домен ограничено, и для решения этой проблемы было использовано разбиение домена .
- Подобный метод оптимизации заключался в объединении нескольких ресурсов (CSS, JavaScript) в один пакет, чтобы можно было получить их одним запросом. Компромисс избавляет от необходимости обходить сеть с риском не использовать некоторые части собранного комплекта ресурсов вообще. В некоторых случаях сложная логика на стороне сервера заботится о выборе подходящих статических ресурсов и объединении их для конкретного запроса страницы
- Спрайты изображений — это метод, аналогичный пакетированию файлов CSS и JavaScript, для уменьшения количества запросов.
- Другой метод заключается во встраивании статических ресурсов в HTML.
3. Краткое введение в HTTP / 2
HTTP / 2 предназначен для облегчения боли, связанной с поддержанием сложной инфраструктуры для HTTP / 1.1, для обеспечения его эффективной работы. Хотя HTTP / 2 по-прежнему обратно совместим с HTTP / 1.1, он больше не является текстовым протоколом. Клиенты устанавливают соединение как HTTP / 1.1-запрос, а также запросы и обновления. С этого момента HTTP / 2 говорит в двоичных фреймах данных.
3.1. HTTP / 2 мультиплексирование
Благодаря мультиплексированию HTTP / 2 все обходные пути HTTP / 1.1, описанные выше, устарели, поскольку одно соединение может обрабатывать несколько двунаправленных потоков, что позволяет клиентам загружать несколько ресурсов по одному соединению одновременно.
3.2. Сжатие заголовка HTTP / 2
Протоколы HTTP 1.x были основаны на тексте и, следовательно, были многословны. Иногда один и тот же набор заголовков HTTP обменивался снова и снова. HTTP / 2 резко снижает требуемую пропускную способность, поддерживая таблицу заголовков HTTP между запросами. По сути, это дедупликация, а не сжатие в классическом смысле.
3.3. HTTP / 2 push
Вы можете подумать, что HTTP / 2 push — это продолжение или какое-то обновление до WebSocket, но это не так. Хотя WebSocket является средством полнодуплексной связи между клиентом и сервером, чтобы сервер мог отправлять данные клиентам после установления TCP-соединения, HTTP / 2 решает отдельную проблему.
HTTP / 2 push — это проактивная отправка ресурсов клиентам без необходимости запрашивать их с точки зрения клиента. Это практически означает, что серверная сторона знает, что веб-сайту нужны некоторые изображения, и отправляет их все сразу (заранее), задолго до того, как клиенты их запросят.
4. Java HTTP клиенты, поддерживающие HTTP / 2
Согласно одной из страниц Wiki HTTP / 2, на момент написания доступны следующие клиентские библиотеки Java для установления соединений HTTP / 2.
- пристань
- Нетти
- OkHttp
- Vert.x
- Светляк
Однако в этой статье мы сконцентрируемся на поддержке HTTP / 2, предоставляемой Java 9. JEP 110 определяет требования, а также заявляет, что проект все еще находится в состоянии инкубации, что практически означает, что он не заменит существующую UrlConnection. API в Java 9.
Только с Java 10 стандартный клиент Java HTTP / 2 будет перемещен в пакет java.net . Тем временем, однако, он будет жить в пространстве имен jdk.incubtor
.
5. Изучите HTTP / 2 клиент Java 9
JEP 110 устанавливает требования для нового встроенного клиента HTTP / 2, чтобы обеспечить высокий уровень, простой в использовании API и сопоставимую (или более высокую) производительность, чем существующие альтернативы (см. Выше).
Первым шагом является импорт модуля jdk.incubator.httpclient
.
1
2
3
|
module com.springui.echo.client { requires jdk.incubator.httpclient; } |
В этом примере мы будем использовать Undertow в качестве HTTP / 2-совместимого веб-сервера. Он просто возвращает то сообщение, которое отправляют ему клиенты.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public class EchoServer { private static final Logger LOGGER = Logger.getLogger(EchoServer. class .getSimpleName()); private static final int PORT = 8888 ; private static final String HOST = "localhost" ; public static void main( final String[] args) { Undertow server = Undertow.builder() .setServerOption(UndertowOptions.ENABLE_HTTP2, true ) .addHttpListener(PORT, HOST) .setHandler(exchange -> { LOGGER.info( "Client address is: " + exchange.getConnection().getPeerAddress().toString()); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain" ); exchange.getRequestReceiver().receiveFullString((e, m) -> e.getResponseSender().send(m)); }).build(); server.start(); } } |
Новый API везде следует шаблону компоновщика , и HttpClient , являющийся точкой входа в инициирование HTTP-запросов, не является исключением из этого.
1
2
3
4
|
HttpClient client = HttpClient .newBuilder() .version(Version.HTTP_2) .build(); |
5.1. Отправка запроса в режиме блокировки
Если у нас есть экземпляр HttpClient, экземпляры HttpRequest также можно создавать с помощью компоновщика.
1
2
3
4
5
6
7
|
HttpResponse<String> response = client.send( HttpRequest .newBuilder(TEST_URI) .POST(BodyProcessor.fromString( "Hello world" )) .build(), BodyHandler.asString() ); |
Метод отправки блока до тех пор, пока обрабатывается запрос, однако есть и способ асинхронного обмена HTTP-сообщениями.
5.2. Отправка запросов в неблокирующем режиме
В следующем примере 10 случайных целых чисел отправляются на наш HTTP-эхо-сервер асинхронно, и когда все запросы были инициированы, основной поток ожидает их завершения.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
List<CompletableFuture<String>> responseFutures = new Random() .ints( 10 ) .mapToObj(String::valueOf) .map(message -> client .sendAsync( HttpRequest.newBuilder(TEST_URI) .POST(BodyProcessor.fromString(message)) .build(), BodyHandler.asString() ) .thenApply(r -> r.body()) ) .collect(Collectors.toList()); CompletableFuture.allOf(responseFutures.toArray( new CompletableFuture<?>[ 0 ])).join(); responseFutures.stream().forEach(future -> { LOGGER.info( "Async response: " + future.getNow( null )); }); |
5.3. Обработка кадров с обещаниями
Все приведенные выше примеры могли бы быть обычными, устаревшими запросами HTTP / 1.1. Помимо создания HttpClient , ничего специфичного для HTTP / 2 не наблюдается.
Вероятно, наиболее важной функцией HTTP / 2 в клиентском API является способ обработки нескольких ответов при использовании HTTP / 2 push.
01
02
03
04
05
06
07
08
09
10
11
|
Map<HttpRequest, CompletableFuture<HttpResponse<String>>> responses = client.sendAsync( HttpRequest.newBuilder(TEST_URI) .POST(BodyProcessor.fromString(TEST_MESSAGE)) .build(), MultiProcessor.asMap(request -> Optional.of(BodyHandler.asString())) ).join(); responses.forEach((request, responseFuture) -> { LOGGER.info( "Async response: " + responseFuture.getNow( null )); }); |
6. Заключение
HTTP / 2 обновляет старый текстовый протокол с очень необходимыми улучшениями и делает многие из грязных обходных путей HTTP / 1.1 устаревшими, однако это не решает все известные проблемы.
С точки зрения Java 9 новый клиент HTTP / 2 выглядит красиво, однако он будет готов к работе только в следующем выпуске. Тем временем вышеупомянутые библиотеки могут быть использованы, если требуется поддержка HTTP / 2.
Обновление: HTTP-клиент JEP 312 предлагает стандартизировать API-интерфейс HTTP-клиента, который был представлен в качестве инкубационного API-интерфейса в Java 9 и обновлен в Java 10. Начиная с Java 11 это полноценная функция модуля java.net
.
Если вы хотите узнать больше о Java 9, вы также можете проверить эти учебники по Java 9 от Java Code Geeks.
См. Оригинальную статью здесь: Введение в поддержку HTTP / 2 в Java 9 Мнения, высказанные участниками Java Code Geeks, являются их собственными. |