1. 概述
HTTP/2 协议最引人注目的特性之一是 服务端推送(Server Push),它允许服务器在客户端发起一次请求后,主动推送多个相关资源。✅
这直接减少了传统 HTTP/1.x 中因多次往返(round-trip)获取资源带来的延迟,显著提升页面加载速度。
Jetty 作为成熟的 Java Web 服务器,对 HTTP/2 提供了完整的客户端和服务端支持。
本文将深入 Jetty 的 HTTP/2 实现机制,并通过一个实战示例,带你直观感受 Server Push 带来的性能飞跃。重点聚焦 如何配置、验证及踩坑提示,避免走弯路。
2. 快速上手
2.1. 下载与环境准备
运行 Jetty 的 HTTP/2 功能,需满足两个硬性条件:
- ✅ JDK 8 或更高版本
- ✅ ALPN(Application-Layer Protocol Negotiation)支持
⚠️ 注意:HTTP/2 在非加密场景(HTTP/2 Clear Text, h2c)支持有限,生产环境强烈建议通过 SSL/TLS 启用 ALPN 来协商 h2 协议。
操作步骤:
- 下载最新版 Jetty
- 解压后设置环境变量
JETTY_HOME
指向解压目录
2.2. 启用 HTTP/2 连接器
使用 Jetty 的模块化启动机制,一行命令即可激活 HTTP/2:
java -jar $JETTY_HOME/start.jar --add-to-start=http2
该命令会:
- 自动在 8443 端口的 SSL 连接器上启用 HTTP/2
- 递归激活
alpn
和ssl
等依赖模块
执行后输出日志如下,重点关注 http2
和 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 : http2 initialized in ${jetty.base}/start.ini
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
INFO : Base directory was modified
2.3. 启动 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
✅ 关键点:{SSL, (ssl, alpn, h2)}
表示 SSL 连接器已支持 h2
协议。
2.4. 启用其他模块
若需同时支持 HTTP/1.1 和 h2c(明文 HTTP/2),可追加模块:
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}
查看所有可用模块:
java -jar $JETTY_HOME/start.jar --list-modules
输出会列出 http2
、alpn
等模块的依赖和配置文件,是排查问题的好帮手。
2.5. 高级配置
使用 --list-config
查看模块对应的 XML 配置文件:
java -jar $JETTY_HOME/start.jar --list-config
在 start.ini
中可自定义关键参数:
# SSL 连接配置
jetty.ssl.host=0.0.0.0
jetty.ssl.port=8443
jetty.ssl.idleTimeout=30000
# HTTP/2 性能调优
jetty.http2.maxConcurrentStreams=128
jetty.http2.initialStreamRecvWindow=524288
jetty.http2.initialSessionRecvWindow=1048576
jetty.http2.maxSettingsKeys=64
jetty.http2.rateControl.maxEventsPerSecond=20
⚠️ 踩坑提示:maxConcurrentStreams
过小可能导致并发推送被限流,生产环境建议根据负载测试调整。
3. 构建 Jetty HTTP/2 应用
3.1. Maven 依赖配置
在 pom.xml
中引入核心依赖:
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.27.v20200227</version>
<dependencies>
<!-- HTTP/2 服务端实现 -->
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
<!-- JDK 8 ALPN 支持 -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
<!-- 包含 PushCacheFilter -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>9.4.27.v20200227</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
编译并启动:
mvn clean package
mvn jetty:run-forked
此时服务默认以 HTTP/1.1 在 8080 端口运行。
3.2. 通过 jetty.xml 配置 HTTP/2
在 src/main/config/jetty.xml
中手动定义 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 和 httpConfig 定义省略 -->
<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">
<!-- SSL 工厂,next 指向 alpn -->
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
<Arg name="sslContextFactory"><Ref id="sslContextFactory"/></Arg>
<Arg name="next">alpn</Arg>
</New>
</Item>
<!-- ALPN 工厂,协商协议优先级 -->
<Item>
<New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
<Arg>h2</Arg>
</New>
</Item>
<!-- HTTP/2 服务端工厂 -->
<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>
</Configure>
在 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>
<!-- JDK 8 必须添加 alpn-boot jar 到 BootClasspath -->
<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>
⚠️ 踩坑提示:JDK 8 需手动引入 alpn-boot
jar,JDK 9+ 已内置 ALPN,无需此步骤。
重启应用,日志应显示:
oejs.AbstractConnector:main: Started ServerConnector@1810399e{SSL, (ssl, alpn, h2)}{0.0.0.0:8444}
3.3. 配置 PushCacheFilter
使用 Jetty 内置的 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> <!-- 仅对 HTTP/2 端口生效 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>push</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
该 Filter 会自动缓存主资源(如 index.html
)关联的静态资源(CSS, JS, 图片),并在响应主资源时主动推送。
3.4. Servlet 配置
创建处理图片请求的 Servlet 并映射路径:
<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. 构建 HTTP/2 客户端测试页
创建 http2.html
,引用多个图片资源以测试推送效果:
<!DOCTYPE html>
<html>
<head>
<title>Jetty HTTP/2 测试</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/1.1)
访问 https://localhost:8443/http2.html
,打开浏览器开发者工具(Network 标签页):
观察到:
- 协议为
http/1.1
- 图片资源需单独发起请求
- 加载耗时约 3-6ms
HTTP/2 + Push 测试
访问 https://localhost:8444/http2.html
:
关键变化:
- ✅ 协议显示为
h2
- ✅ 图片资源的 Initiator 为
Push
,表明由服务端主动推送 - ✅ 所有图片加载时间降至 1ms
✅ 结论:PushCacheFilter
成功将关联的静态资源预先推送到客户端,页面加载性能得到质的飞跃。
6. 总结
本文系统性地演示了如何在 Jetty 中启用并验证 HTTP/2 及 Server Push 功能:
- 通过模块化命令或
jetty.xml
配置 HTTP/2 连接器 - 正确处理 JDK 8 的 ALPN 依赖
- 使用
PushCacheFilter
简单粗暴地实现资源预推送 - 通过浏览器工具直观对比性能差异
核心价值在于减少关键资源的获取延迟。实际应用中,合理利用 Push 可显著优化首屏渲染时间。完整代码已托管至 GitHub,可直接拉取参考。
GitHub 源码:https://github.com/baeldung/tutorials/tree/master/libraries-server-2