1. Overview
1.概述
The HTTP/2 protocol comes with a push feature that allows the server to send multiple resources to the client for a single request. Hence, it improves the loading time of the page by reducing the multiple round-trips needed to fetch all the resources.
HTTP/2协议带有推送功能,允许服务器为单个请求向客户端发送多个资源。因此,它通过减少获取所有资源所需的多次往返,来改善页面的加载时间。
Jetty supports the HTTP/2 protocol for both client and server implementations.
Jetty支持客户端和服务器实现的 HTTP/2 协议。
In this tutorial, we’ll explore HTTP/2 support in Jetty and create a Java web application to examine the HTTP/2 Push feature.
在本教程中,我们将探索Jetty中的HTTP/2支持,并创建一个Java Web应用程序来检查HTTP/2推送功能。。
2. Getting Started
2.入门
2.1. Downloading Jetty
2.1.下载Jetty
Jetty requires JDK 8 or later and ALPN (Application-Layer Protocol Negotiation) support for running HTTP/2.
Jetty需要JDK 8或更高版本,并支持ALPN(应用层协议协商)以运行HTTP/2。
Typically, the Jetty server is deployed over SSL and enables the HTTP/2 protocol via the TLS extension (ALPN).
通常情况下,Jetty服务器通过SSL部署,并通过TLS扩展(ALPN)启用HTTP/2协议。
First, we’ll need to download the latest Jetty distribution and set the JETTY_HOME variable.
首先,我们需要下载最新的Jetty发行版并设置JETTY_HOME变量。
2.2. Enabling the HTTP/2 Connector
2.2.启用HTTP/2连接器
Next, we can use a Java command to enable the HTTP/2 connector on the Jetty server:
接下来,我们可以使用一个Java命令来启用Jetty服务器上的HTTP/2连接器。
java -jar $JETTY_HOME/start.jar --add-to-start=http2
This command adds HTTP/2 protocol support to the SSL connector on port 8443. Also, it transitively enables the ALPN module for protocol negotiation:
该命令为SSL连接器增加了HTTP/2协议支持,端口为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
Here, the logs show the information of modules like ssl and alpn-impl/alpn-8 that are transitively enabled for the HTTP/2 connector.
这里,日志显示了像ssl和alpn-impl/alpn-8这样的模块的信息,这些模块是为HTTP/2连接器过境启用的。
2.3. Starting the Jetty Server
2.3.启动Jetty服务器
Now, we’re ready to start the Jetty server:
现在,我们准备启动Jetty服务器。
java -jar $JETTY_HOME/start.jar
When the server starts, the logging will show the modules that are enabled:
当服务器启动时,日志将显示已启用的模块。
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. Enabling Additional Modules
2.4.启用附加模块
Similarly, we can enable other modules like http and http2c:
同样地,我们可以启用其他模块,如http和http2c。
java -jar $JETTY_HOME/start.jar --add-to-start=http,http2c
Let’s verify the logs:
让我们验证一下日志。
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
Also, we can list all the modules provided by Jetty:
另外,我们可以列出Jetty提供的所有模块。
java -jar $JETTY_HOME/start.jar --list-modules
The output will look like:
输出将看起来像。
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. Additional Configuration
2.5.额外配置
Similar to the –list-modules argument, we can use –list-config to list all the XML config files for each module:
与-list-modules参数类似,我们可以使用-list-config来列出每个模块的所有XML配置文件。
java -jar $JETTY_HOME/start.jar --list-config
To configure the common properties like host and port for the Jetty server, we can make changes in the start.ini file:
为了配置Jetty服务器的常用属性,如host和port,我们可以在start.ini文件中进行修改。
jetty.ssl.host=0.0.0.0
jetty.ssl.port=8443
jetty.ssl.idleTimeout=30000
Also, there are a few http2 properties like maxConcurrentStreams and maxSettingsKeys that we can configure:
此外,还有一些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. Setting Up a Jetty Server Application
3.设置一个Jetty服务器应用程序
3.1. Maven Configuration
3.1.Maven配置
Now that we’ve got Jetty configured, it’s time to create our application.
现在我们已经配置好了Jetty,是时候创建我们的应用程序了。
Let’s add the jetty-maven-plugin Maven plugin to our pom.xml along with Maven dependencies like http2-server, jetty-alpn-openjdk8-server, and jetty-servlets:
让我们把jetty-maven-plugin Maven插件和pom.xml以及http2-server、jetty-alpn-openjdk8-server、jetty-servlets等Maven依赖项添加到我们的 pom.xml。
<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>
Then, we’ll compile the classes using the Maven command:
然后,我们将使用Maven命令编译这些类。
mvn clean package
And lastly, we can deploy our unassembled Maven app to the Jetty server:
最后,我们可以将未组装的Maven应用部署到Jetty服务器上。
mvn jetty:run-forked
By default, the server starts on port 8080 with the HTTP/1.1 protocol:
默认情况下,服务器从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. Configure HTTP/2 in jetty.xml
3.2.在jetty.xml中配置HTTP/2
Next, we’ll configure the Jetty server with the HTTP/2 protocol in our jetty.xml file by adding the appropriate Call element:
接下来,我们将在jetty.xml文件中通过添加适当的Call元素来配置Jetty服务器的HTTP/2协议。
<?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>
Here, the HTTP/2 connector is configured with ALPN on port 8444 along with sslContextFactory and httpConfig configs.
在这里,HTTP/2连接器与8444端口的ALPN以及sslContextFactory和httpConfig配置一起被配置。
Also, we can add other modules like h2-17 and h2-16 (draft versions of h2) by defining comma-separated arguments in jetty.xml:
另外,我们可以通过在jetty.xml中定义逗号分隔的参数来添加其他模块,如h2-17和h2-16(h2的草案版本)。
<Item>
<New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
<Arg>h2,h2-17,h2-16</Arg>
</New>
</Item>
Then, we’ll configure the location of the jetty.xml in our pom.xml:
然后,我们将在pom.xml中配置jetty.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>
Note: To enable HTTP/2 in our Java 8 app, we’ve added the alpn-boot jar to the JVM BootClasspath. However, ALPN support is already available in Java 9 or later.
注意:为了在我们的 Java 8 应用程序中启用 HTTP/2,我们已经将 alpn-boot jar 添加到 JVM BootClasspath。然而,ALPN 支持在 Java 9 或更高版本中已经可用。
Let’s re-compile our classes and re-run the application to verify if the HTTP/2 protocol is enabled:
让我们重新编译我们的类,并重新运行应用程序,以验证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}
Here, we can observe that port 8443 is configured with the HTTP/1.1 protocol and 8444 with HTTP/2.
在这里,我们可以看到,端口8443被配置为HTTP/1.1协议,8444被配置为HTTP/2。
3.3. Configure the PushCacheFilter
3.3.配置PushCacheFilter
Next, we need a filter that pushes the secondary resources like images, JavaScript, and CSS to the client.
接下来,我们需要一个过滤器,将图片、JavaScript和CSS等次级资源推送到客户端。
To do so, we can use the PushCacheFilter class available in the org.eclipse.jetty.servlets package. PushCacheFilter builds a cache of secondary resources associated with a primary resource like index.html and pushes them to the client.
为此,我们可以使用org.eclipse.jetty.servlets包中的PushCacheFilter/a>类。PushCacheFilter构建了一个与主资源(如index.html)相关联的二级资源缓存,并将其推送到客户端。
Let’s configure the PushCacheFilter in our web.xml:
让我们在web.xml中配置PushCacheFilter。
<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. Configure Jetty Servlet and Servlet Mapping
3.4.配置Jetty Servlet和Servlet映射
Then, we’ll create the Http2JettyServlet class to access the images, and we’ll add the servlet-mapping in our web.xml file:
然后,我们将创建Http2JettyServlet类来访问图像,我们将在web.xml文件中添加servlet-mapping。
<servlet>
<servlet-name>http2Jetty</servlet-name>
<servlet-class>com.baeldung.jetty.http2.Http2JettyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>http2Jetty</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>
4. Setting up the HTTP/2 Client
4.设置HTTP/2客户端
Finally, to verify the HTTP/2 Push feature and the improved page-load time, we’ll create an http2.html file that loads a few images (secondary resources):
最后,为了验证HTTP/2推送功能和改进的页面加载时间,我们将创建一个http2.html文件,加载一些图片(二级资源)。
<!DOCTYPE html>
<html>
<head>
<title>Baeldung 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. Testing the HTTP/2 Client
5.测试HTTP/2客户端
To get a baseline for the page-load time, let’s access the HTTP/1.1 application at https://localhost:8443/http2.html with the Developer Tools to verify the protocol and load time:
为了得到一个页面加载时间的基线,让我们用开发者工具访问HTTP/1.1应用程序,地址是https://localhost:8443/http2.html,以验证协议和加载时间。
Here, we can observe that the images are loaded in 3-6ms using the HTTP/1.1 protocol.
在这里,我们可以观察到,使用HTTP/1.1协议,图像的加载时间为3-6ms。
Then, we’ll access the HTTP/2 application, which has Push enabled, at https://localhost:8444/http2.html:
然后,我们将在https://localhost:8444/http2.html访问已启用Push的HTTP/2应用程序。
Here, we observe that the protocol is h2, the initiator is Push, and the loading time is 1ms for all the images (secondary resources).
在这里,我们观察到协议是h2,发起人是Push,所有图像(二级资源)的加载时间是1ms。
Therefore, the PushCacheFilter caches the secondary resources for http2.html, pushes them on port 8444, and provides a great improvement in the load time of the page.
因此,PushCacheFilter为http2.html缓存二级资源,将其推送到8444端口,并为页面的加载时间提供了极大的改善。
6. Conclusion
6.结语
In this tutorial, we’ve explored HTTP/2 in Jetty.
在本教程中,我们已经探索了Jetty中的HTTP/2。
First, we examined how to start Jetty with the HTTP/2 protocol along with its configurations.
首先,我们研究了如何用HTTP/2协议启动Jetty以及它的配置。
Then, we’ve seen a Java 8 web application with the HTTP/2 Push feature, configured with a PushCacheFilter, and observed how the load time of a page containing secondary resources improved over what we saw with the HTTP/1.1 protocol.
然后,我们看到一个具有HTTP/2推送功能的Java 8网络应用,配置了一个PushCacheFilter,并观察到包含二级资源的页面的加载时间比我们在HTTP/1.1协议下看到的有所改善。
As usual, all the code implementations are available over on GitHub.
像往常一样,所有的代码实现都可以在GitHub上找到,。