Перейти к основному содержимому

HTTP/2 в пристани

· 7 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

Протокол HTTP/2 поставляется с функцией push, которая позволяет серверу отправлять несколько ресурсов клиенту для одного запроса . Следовательно, это улучшает время загрузки страницы за счет сокращения количества циклов, необходимых для получения всех ресурсов.

Jetty поддерживает протокол HTTP/2 как для клиентской, так и для серверной реализации.

В этом руководстве мы рассмотрим поддержку HTTP/2 в Jetty и создадим веб-приложение Java для изучения функции HTTP/2 Push .

2. Начало работы

2.1. Загрузка пристани

Jetty требуется JDK 8 или более поздняя версия и поддержка ALPN (согласование протокола уровня приложений) для работы HTTP/2.

Как правило, сервер Jetty развертывается через SSL и включает протокол HTTP/2 через расширение TLS (ALPN) .

Во-первых, нам нужно загрузить последний дистрибутив Jetty и установить переменную JETTY_HOME .

2.2. Включение коннектора HTTP/2

Затем мы можем использовать команду Java, чтобы включить коннектор HTTP/2 на сервере Jetty:

java -jar $JETTY_HOME/start.jar --add-to-start=http2

Эта команда добавляет поддержку протокола HTTP/2 в коннектор SSL на порту 8443 . Кроме того, он транзитивно включает модуль ALPN для согласования протокола:

INFO  : server          transitively enabled, ini template available with --add-to-start=server
INFO : alpn-impl/alpn-1.8.0_131 dynamic dependency of alpn-impl/alpn-8
INFO : alpn-impl transitively enabled
INFO : alpn transitively enabled, ini template available with --add-to-start=alpn
INFO : alpn-impl/alpn-8 dynamic dependency of alpn-impl
INFO : http2 initialized in ${jetty.base}/start.ini
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
INFO : threadpool transitively enabled, ini template available with --add-to-start=threadpool
INFO : bytebufferpool transitively enabled, ini template available with --add-to-start=bytebufferpool
INFO : Base directory was modified

Здесь журналы показывают информацию о таких модулях, как ssl и alpn-impl/alpn-8 , которые транзитивно включены для коннектора HTTP/2.

2.3. Запуск Jetty-сервера

Теперь мы готовы запустить сервер Jetty:

java -jar $JETTY_HOME/start.jar

Когда сервер запустится, журнал покажет включенные модули:

INFO::main: Logging initialized @228ms to org.eclipse.jetty.util.log.StdErrLog
...
INFO:oejs.AbstractConnector:main: Started ServerConnector@42dafa95{SSL, (ssl, alpn, h2)}{0.0.0.0:8443}
INFO:oejs.Server:main: Started @872ms

2.4. Включение дополнительных модулей

Точно так же мы можем включить другие модули, такие как http и http2c :

java -jar $JETTY_HOME/start.jar --add-to-start=http,http2c

Давайте проверим журналы:

INFO:oejs.AbstractConnector:main: Started ServerConnector@6adede5{SSL, (ssl, alpn, h2)}{0.0.0.0:8443}
INFO:oejs.AbstractConnector:main: Started ServerConnector@dc24521{HTTP/1.1, (http/1.1, h2c)}{0.0.0.0:8080}
INFO:oejs.Server:main: Started @685ms

Также мы можем перечислить все модули, предоставляемые Jetty:

java -jar $JETTY_HOME/start.jar --list-modules

Вывод будет выглядеть так:

Available Modules:
==================
tags: [-internal]
Modules for tag '*':
--------------------
Module: alpn
: Enables the ALPN (Application Layer Protocol Negotiation) TLS extension.
Depend: ssl, alpn-impl
LIB: lib/jetty-alpn-client-${jetty.version}.jar
LIB: lib/jetty-alpn-server-${jetty.version}.jar
XML: etc/jetty-alpn.xml
Enabled: transitive provider of alpn for http2
// ...

Modules for tag 'connector':
----------------------------
Module: http2
: Enables HTTP2 protocol support on the TLS(SSL) Connector,
: using the ALPN extension to select which protocol to use.
Tags: connector, http2, http, ssl
Depend: ssl, alpn
LIB: lib/http2/*.jar
XML: etc/jetty-http2.xml
Enabled: ${jetty.base}/start.ini
// ...

Enabled Modules:
================
0) alpn-impl/alpn-8 dynamic dependency of alpn-impl
1) http2 ${jetty.base}/start.ini
// ...

2.5. Дополнительная конфигурация

Подобно аргументу --list-modules , мы можем использовать --list-config для вывода списка всех файлов конфигурации XML для каждого модуля:

java -jar $JETTY_HOME/start.jar --list-config

Чтобы настроить общие свойства, такие как хост и порт для сервера Jetty, мы можем внести изменения в файл start.ini :

jetty.ssl.host=0.0.0.0
jetty.ssl.port=8443
jetty.ssl.idleTimeout=30000

Кроме того, есть несколько свойств http2, таких как maxConcurrentStreams и maxSettingsKeys , которые мы можем настроить: ``

jetty.http2.maxConcurrentStreams=128
jetty.http2.initialStreamRecvWindow=524288
jetty.http2.initialSessionRecvWindow=1048576
jetty.http2.maxSettingsKeys=64
jetty.http2.rateControl.maxEventsPerSecond=20

3. Настройка приложения Jetty Server

3.1. Конфигурация Maven

Теперь, когда мы настроили Jetty, пришло время создать наше приложение.

Давайте добавим плагин Maven jetty -maven- plugin в наш pom.xml вместе с зависимостями Maven, такими как http2-server , jetty-alpn-openjdk8-server и jetty -servlets :

<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.27.v20200227</version>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

Затем мы скомпилируем классы с помощью команды Maven:

mvn clean package

И, наконец, мы можем развернуть наше несобранное приложение Maven на сервере Jetty:

mvn jetty:run-forked

По умолчанию сервер запускается на порту 8080 с протоколом HTTP/1.1:

oejmp.Starter:main: Started Jetty Server
oejs.AbstractConnector:main: Started ServerConnector@4d910fd6{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
oejs.Server:main: Started @1045ms

3.2. Настройте HTTP/2 в jetty.xml

Далее мы настроим сервер Jetty с протоколом HTTP/2 в нашем файле jetty.xml , добавив соответствующий элемент Call :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- sslContextFactory and httpConfig configs-->

<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref id="Server"/></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
<Arg name="sslContextFactory"><Ref id="sslContextFactory"/></Arg>
<Arg name="next">alpn</Arg>
</New>
</Item>
<Item>
<New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
<Arg>h2</Arg>
</New>
</Item>
<Item>
<New class="org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory">
<Arg name="config"><Ref id="httpConfig"/></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="port">8444</Set>
</New>
</Arg>
</Call>

<!-- other Call elements -->
</Configure>

Здесь коннектор HTTP/2 настроен с помощью ALPN на порту 8444 вместе с конфигурациями sslContextFactory и httpConfig .

Кроме того, мы можем добавить другие модули, такие как h2-17 и h2-16 (черновые версии h2 ), определив аргументы, разделенные запятыми, в jetty.xml :

<Item> 
<New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
<Arg>h2,h2-17,h2-16</Arg>
</New>
</Item>

Затем мы настроим расположение jetty.xml в нашем pom.xml :

<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.27.v20200227</version>
<configuration>
<stopPort>8888</stopPort>
<stopKey>quit</stopKey>
<jvmArgs>
-Xbootclasspath/p:
${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar
</jvmArgs>
<jettyXml>${basedir}/src/main/config/jetty.xml</jettyXml>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
...
</plugin>

Примечание. Чтобы включить HTTP/2 в нашем приложении Java 8, мы добавили jar alpn-boot в JVM BootClasspath . Однако поддержка ALPN уже доступна в Java 9 и более поздних версиях .

Давайте перекомпилируем наши классы и повторно запустим приложение, чтобы проверить, включен ли протокол HTTP/2:

oejmp.Starter:main: Started Jetty Server
oejs.AbstractConnector:main: Started ServerConnector@6fadae5d{SSL, (ssl, http/1.1)}{0.0.0.0:8443}
oejs.AbstractConnector:main: Started ServerConnector@1810399e{SSL, (ssl, alpn, h2)}{0.0.0.0:8444}

Здесь мы видим, что порт 8443 настроен для протокола HTTP/1.1, а порт 8444 — для HTTP/2.

3.3. Настройка PushCacheFilter

Затем нам нужен фильтр, который отправляет клиенту вторичные ресурсы, такие как изображения, JavaScript и CSS.

Для этого мы можем использовать класс PushCacheFilter , доступный в пакете org.eclipse.jetty.servlets . PushCacheFilter создает кэш вторичных ресурсов, связанных с первичным ресурсом, таким как index.html , и отправляет их клиенту.

Давайте настроим PushCacheFilter в нашем web.xml :

<filter>
<filter-name>push</filter-name>
<filter-class>org.eclipse.jetty.servlets.PushCacheFilter</filter-class>
<init-param>
<param-name>ports</param-name>
<param-value>8444</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>push</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

3.4. Настройка сервлета Jetty и сопоставления сервлетов

Затем мы создадим класс Http2JettyServlet для доступа к изображениям и добавим отображение сервлета в наш файл web.xml :

<servlet>
<servlet-name>http2Jetty</servlet-name>
<servlet-class>com.foreach.jetty.http2.Http2JettyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>http2Jetty</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>

4. Настройка клиента HTTP/2

Наконец, чтобы проверить функцию HTTP/2 Push и улучшенное время загрузки страницы, мы создадим файл http2.html , который загружает несколько изображений (вторичных ресурсов):

<!DOCTYPE html>
<html>
<head>
<title>ForEach HTTP/2 Client in Jetty</title>
</head>
<body>
<h2>HTTP/2 Demo</h2>
<div>
<img src="images/homepage-latest_articles.jpg" alt="latest articles" />
<img src="images/homepage-rest_with_spring.jpg" alt="rest with spring" />
<img src="images/homepage-weekly_reviews.jpg" alt="weekly reviews" />
</div>
</body>
</html>

5. Тестирование клиента HTTP/2

Чтобы получить базовый показатель времени загрузки страницы, давайте получим доступ к приложению HTTP/1.1 по адресу https://localhost:8443/http2.html с помощью инструментов разработчика, чтобы проверить протокол и время загрузки:

./ca1c2e23110cd52eb5a178621c719756.png

Здесь мы можем наблюдать, что изображения загружаются за 3-6 мс по протоколу HTTP/1.1.

Затем мы получим доступ к приложению HTTP/2, в котором включена функция Push, по адресу https://localhost:8444/http2.html :

./05960301bfcf3d35476da60c845f5ff5.png

Здесь мы видим, что протокол — h2 , инициатор — Push , а время загрузки — 1 мс для всех изображений (вторичных ресурсов).

Таким образом, PushCacheFilter кэширует вторичные ресурсы для http2.html, отправляет их на порт 8444 и значительно сокращает время загрузки страницы.

6. Заключение

В этом руководстве мы изучили HTTP/2 в Jetty.

Во-первых, мы рассмотрели, как запустить Jetty с протоколом HTTP/2 вместе с его конфигурациями.

Затем мы увидели веб-приложение Java 8 с функцией HTTP/2 Push, настроенное с помощью PushCacheFilter , и наблюдали, как время загрузки страницы, содержащей вторичные ресурсы, улучшилось по сравнению с тем, что мы видели с протоколом HTTP/1.1.

Как обычно, все реализации кода доступны на GitHub .