
在之前的文章中,我们介绍了Nginx反向代理gRPC服务,而gRPC正是基于HTTP/2实现的。相比于HTTP/1.1,HTTP/2.0协议在性能上带来了显著的提升。尽管作者在之前的Nginx演示配置中已多次开启HTTP/2支持,但并未深入探讨其具体优势与功能。因此,本文将详细介绍HTTP/2的核心特性,并重点演示如何在Nginx中配置并实践其强大的服务器资源推送功能。
HTTP2 协议介绍
HTTP/2作为HTTP协议的第二个主要版本,于2015年发布。它旨在解决HTTP/1.x的性能瓶颈,提升网页加载速度和网络效率,核心改进包括解决队头阻塞、减少连接开销以及压缩冗余头部。目前,HTTP/2已成为现代互联网的主流协议。

HTTP/2.0 协议构建于几个核心概念之上:
- 连接(Connection):一个TCP连接,可以承载多个双向数据流。
- 流(Stream):存在于连接中的双向通信数据流,每个请求/响应对应一个流,包含多个消息。
- 消息(Message):一个完整的请求或响应,由一或多个帧组成。
- 帧(Frame):最小的通信单元,采用二进制格式,承载HTTP头部或数据体。

帧是HTTP/2通信的基础,其格式包含长度、类型、标志、流标识符以及负载数据,如下图所示:

HTTP/2 带来的主要特性与改进包括:
- 二进制传输(核心):告别HTTP/1.x的文本格式,改用二进制帧进行传输,解析更快、更高效,且错误率更低。
- 头部压缩(核心):采用HPACK算法压缩请求头,大幅减少Cookie、User-Agent等冗余数据的传输,节省带宽。该算法结合了静态字典、动态字典和Huffman编码。

- 多路复用(核心):允许在单个TCP连接上并行交错传输多个请求和响应,帧可以根据需要组合,彻底解决了HTTP/1.x中的队头阻塞问题,显著提升并发效率,也避免了频繁建立连接的开销。

- 服务器推送:服务器可以主动预测客户端需求,并行推送相关资源(如CSS、JS文件),减少额外的请求延迟。

- 请求优先级:允许客户端为请求分配优先级权重,确保关键资源(如HTML)优先加载,优化页面渲染体验。

- 安全性提升:主流浏览器通常只支持基于TLS/1.2+加密的HTTP/2,推动了全站HTTPS的普及。
HTTP/2.0 与 HTTP/1.x 的核心对比如下:
| 特性 |
HTTP/1.0 |
HTTP/1.1 |
HTTP/2 |
说明与影响 |
| 协议格式 |
文本协议 |
文本协议 |
二进制协议 |
HTTP/2使用二进制帧,解析效率高,错误率低。 |
| 连接管理 |
短连接(默认) |
持久连接(默认) |
单连接多路复用 |
单个TCP连接处理多个并行流,极大减少连接开销。 |
| 并发请求 |
每个请求需新连接 |
多个TCP连接(6-8个/域名) |
单个连接内多路复用 |
彻底解决应用层队头阻塞,无需域名分片等优化。 |
| 头部传输 |
不压缩 |
不压缩 |
HPACK头部压缩 |
减少重复头部传输,节省带宽可达40-90%。 |
| 服务器推送 |
不支持 |
不支持 |
支持 |
服务器可主动推送CSS/JS等资源,减少请求延迟。 |
| 请求优先级 |
无 |
无 |
流优先级控制 |
客户端可指定资源加载优先级。 |
| 安全要求 |
无 |
无 |
事实上的TLS要求 |
主流浏览器只支持加密的HTTP/2(h2)。 |

此外,HTTP/2也为后续的HTTP/3奠定了基础,HTTP/3改用基于UDP的QUIC协议,旨在进一步解决TCP固有的队头阻塞和握手延迟问题。
了解了HTTP/2的核心优势后,我们将在Nginx中实践如何启用它并体验其服务器推送功能。首先,需要了解Nginx中相关的配置指令。
Nginx HTTP/2 模块指令
要使Nginx完全支持HTTP/2,必须在编译时启用 --with-http_v2_module 选项来安装 ngx_http_v2_module 模块。同时,由于主流实现要求,必须配置TLS/SSL证书以启用HTTPS。
# 构建脚本示例
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module ...
make -j$(nproc) && make install
核心指令
http2:在监听指令中启用HTTP/2支持。
Syntax: http2 on | off;
Default: http2 off;
Context: http, server
示例:
server {
listen 443 ssl http2; # 在listen指令中直接启用
ssl_certificate server.crt;
ssl_certificate_key server.key;
# ... 其他配置
}
注意:自Nginx 1.25.1起,推荐直接在listen指令中添加http2参数。
服务器推送指令(已废弃)
重要提示:自 Nginx 1.25.1 版本起,以下用于配置服务器推送的指令已被废弃,使用它们会被Nginx忽略并产生警告。应改用Link响应头实现推送。
http2_push:指定要推送的URI。
http2_push_preload:启用对Link响应头中预加载提示的处理。
连接与流控制指令(部分已废弃)
http2_max_concurrent_streams:设置一个连接中并发HTTP/2流的最大数量。
Syntax: http2_max_concurrent_streams number;
Default: http2_max_concurrent_streams 128;
Context: http, server
http2_chunk_size:设置响应正文分块的最大大小,影响优先级和队头阻塞。
Syntax: http2_chunk_size size;
Default: http2_chunk_size 8k;
Context: http, server, location
http2_max_requests, http2_idle_timeout等指令已废弃,建议分别使用标准的keepalive_requests和keepalive_timeout指令代替。
内置变量
该模块提供了一个内置变量 $http2,用于标识当前连接的HTTP/2状态:
“h2”: 基于TLS的HTTP/2连接。
“h2c”: 基于明文TCP的HTTP/2连接。
- 空字符串: 非HTTP/2连接。
实践演示:在Nginx中启用HTTP/2与服务器推送
下面通过一个完整的示例,演示如何配置Nginx以支持HTTP/2,并使用现代方式(Link头)实现服务器资源推送。
步骤 1:准备环境
准备静态资源文件(HTML、CSS、JS、图片、视频)以及SSL证书(自签名或由CA颁发)。
$ tree /usr/local/nginx/html
.
├── index.html
├── video.html
├── css/
│ └── style.css
├── js/
│ └── index.js
├── img/
│ └── bg.png
└── videos/
└── 202403192224.mp4
步骤 2:配置Nginx
创建server配置文件,启用HTTP/2,并通过add_header Link设置服务器推送。
# /usr/local/nginx/conf.d/server.conf
map $http2 $push_allowed {
default "";
"h2" "1"; # 仅当连接为HTTP/2时允许推送
}
server {
listen 443 ssl http2; # 启用SSL和HTTP/2
server_name server.weiyigeek.top;
# SSL证书配置
ssl_certificate /usr/local/nginx/certs/server.crt;
ssl_certificate_key /usr/local/nginx/certs/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
# ... 其他SSL优化配置
root /usr/local/nginx/html;
index index.html;
# 通用位置块,访问首页时推送CSS和JS
location / {
# 使用Link头部预加载并推送资源
add_header Link "</css/style.css>; as=style; rel=preload, </js/index.js>; as=script; rel=preload" always;
expires 1h;
add_header Cache-Control "public, no-cache";
}
# 特定页面(video.html)推送更多资源
location = /video.html {
if ($push_allowed) {
# 推送CSS和视频文件
add_header Link "</css/style.css>; as=style; rel=preload, </videos/202403192224.mp4>; as=video; type=video/mp4; rel=preload" always;
# 可选:推送封面图片
add_header Link "</img/bg.png>; as=image; rel=preload" always;
}
expires 1h;
add_header Cache-Control "public, no-cache";
}
# 注意:以下旧式推送方法已失效,配置了也会被忽略
location /old {
http2_push /css/style.css; # 已废弃,无效
http2_push /videos/202403192224.mp4; # 已废弃,无效
}
}
配置完成后,验证并重载Nginx。
nginx -t && nginx -s reload
# 可能会看到关于`http2_push`已废弃的警告,这是正常的。
步骤 3:使用工具测试HTTP/2
可以使用支持HTTP/2的客户端工具进行测试,例如新版本的curl或专门的nghttp工具。
-
安装nghttp2工具(以源码编译为例):
wget https://github.com/nghttp2/nghttp2/releases/download/v1.68.0/nghttp2-1.68.0.tar.xz
tar -xf nghttp2-1.68.0.tar.xz
cd nghttp2-1.68.0
./configure --enable-app
make && sudo make install
-
使用nghttp测试连接与推送:
# 测试首页,查看是否能协商为HTTP/2及接收推送
/usr/local/bin/nghttp -ans --no-verify https://server.weiyigeek.top/
输出结果会显示通过HTTP/2接收到的资源,服务器推送的资源会被标记为“pushed”。

- 使用浏览器开发者工具查看:
在Chrome或Firefox中打开https://server.weiyigeek.top/video.html,进入“网络”(Network)标签页。查看请求列表,如果配置成功,style.css、202403192224.mp4等资源的“大小”(Size)列可能会显示“Push”或“(推送)”,表示它们是由服务器主动推送的,而非浏览器主动发起请求。

步骤 4:验证推送效果
查看Nginx的访问日志,可以观察到当请求index.html或video.html时,关联的推送资源(如CSS、JS文件)的请求也会被记录,尽管前端页面并未显式请求它们,这证明了服务器推送正在工作。

总结
本文详细介绍了HTTP/2协议相较于HTTP/1.x在多路复用、头部压缩和服务器推送等方面的核心优势。重点讲解了在Nginx中启用HTTP/2支持的编译与配置方法,并针对Nginx 1.25.1及以上版本,演示了如何通过标准的Link响应头来实现服务器主动推送资源,替代了已废弃的http2_push指令。
通过正确配置,可以显著提升网站的性能与用户体验,尤其是在资源依赖较多的场景下。如果你想深入了解更多关于网络协议的优化或Nginx的高阶运维技巧,可以持续关注相关的技术社区和文档。