Nginx 中 http2 协议介绍与服务搭建资源推送 描述:前面《Nginx | HTTP 反向代理:gRPC 高性能远程过程调用(RPC)框架 》文章中,我们介绍了 Google 推出的 gRPC 服务框架,并在 Nginx 反向代理 gPRC 服务时它也是基于 HTTP/2 实现的,HTTP2.0 协议相对于 HTP1.1 协议有很大的一个性能提升。另外,作者前面的 Nginx 演示配置中都开启了 HTTP/2 支持,但是并未对其详细介绍,和对性能到底有那些提升,以及演示其资源推送功能,所以接下来我们一一详细介绍与实践。
HTTP2 协议介绍 HTTP/2 是 HTTP 协议的第二个主要版本,于 2015 年发布,旨在解决 HTTP/1.x 的性能瓶颈,提升网页加载速度和网络效率,解决了队头阻塞(HTTP/1.x 中一个请求阻塞后续请求),高延迟(减少多次 TCP 连接和握手开销)以及头部冗余(重复的头部字段占用带宽),显著提升了 Web 性能,HTTP/2 已成为现代互联网的主流协议被广泛使用。
weiyigeek.top-作者个人网站启用HTTP/2.0图
HTTP/2.0 协议的核心概念:
连接(Connection):单个 TCP 连接,可以承载多个双向数据流(Stream)
流(Stream):双向通讯的数据流,每个页面可能对应一个Stream,每个流可以包含多个消息
消息(Message):每个消息包含1个或多个帧,对应 HTTP/1.x 请求和响应
帧(Frame):最小概念单元,以二进制压缩格式存储 HTTP/1.x 内容,包括 Headers 和 Data
weiyigeek.top-HTTP/2.0 协议的核心与分层图
此文,我们再详细的介绍一下 Frame 帧的格式,如下图所示:包含长度、类型、标识,消息号(4字节32位)以及数据内容等。
weiyigeek.top-HTTP/2.0 协议帧格式图
HTTP/2 主要特性与改进:
[x] 二进制传输(核心): 将文本格式(HTTP/1.x)改为二进制格式,解析更快、更高效,且减少错误。
[x] 头部压缩(核心): 使用 HPACK 算法压缩请求头,减少冗余数据(如 Cookie、User-Agent),降低带宽消耗,例如:相似请求间仅传输变化部分,大幅度减少重复头部信息的传输,算法主要包含三个部分:
静态字典:将常用的 header 字段整成字典,比如 {"method":"GET"} 就可以用单个数字 2 来表示。 动态字典:没有在静态字典里面的一些头部字段,则用动态字典。
weiyigeek.top-HTTP/2.0 头部压缩图
[x] 多路复用(核心): 允许在单个 TCP 连接上并行传输多个请求和响应,即传输中无序,接收时组装(利用缓存),解决了 HTTP/1.x 的队头阻塞问题,大幅提升并发效率,减少了我们的三次握手和四次握手的开关连接的一个过程,工作效率也最高。
weiyigeek.top-HTTP/2.0 多路复用图
[x] 服务器资源推送: 服务器可以主动向客户端并行推送资源(如 HTML、CSS、JS),减少额外的请求延迟,
weiyigeek.top-HTTP/2.0 资源推送图
[x] 自定义资源优先级:允许客户端为请求分配优先级,确保重要资源(如 HTML)优先传输,例如在某些场景中CSS 可能对重要,需要先给浏览器进行渲染。
weiyigeek.top-HTTP/2.0 资源优先级图
[x] 更安全的默认要求:主流浏览器仅支持加密的 HTTP/2(基于 TLS/1.2+),即必须SSL全站加密,而非明文传输才能真正使用 HTTP/2。
HTTP/2.0 与 HTTP/1.x 对比如下表格所示:
特性 HTTP/1.0 HTTP/1.1 HTTP/2 说明与影响 协议格式 HTTP/2使用二进制帧传输,解析效率更高,错误率更低 连接管理 HTTP/2单个TCP连接可处理多个并行流,减少连接开销 并发请求 HTTP/2彻底解决队头阻塞,无需域名分片等优化技巧 头部传输 减少重复头部传输(如Cookie、User-Agent),节省带宽40-90% 数据压缩 服务器推送 服务器可预测客户端需求,提前推送CSS/JS等资源 请求优先级 客户端可指定资源加载优先级(如HTML优先于图片) 队头阻塞 HTTP/2仍受TCP队头阻塞影响,但应用层已优化 安全要求 主流浏览器只支持加密的HTTP/2(h2),非加密的h2c较少用 握手开销 HTTP/2减少TCP和TLS握手次数,提升加载速度 协议协商 通过TLS的ALPN在握手时协商HTTP/2,无需额外往返 错误处理 支持重置流(RST_STREAM)而不关闭整个连接 流量控制 典型延迟 头部大小限制 缓存策略
weiyigeek.top-http1.0VS2.0图
另外,HTTP/2 为 HTTP/3 奠定了基础,HTTP/3 改用 QUIC 协议(基于 UDP),进一步解决 TCP 的队头阻塞和连接延迟问题。
好了,上面我们介简单绍了 HTTP/2.0 相关特性以及与 HTTP 1.x 协议的对比,下面我们将在 Nginx 中搭建一个 HTTP/2.0 服务,查看到 HTTP 2.0 的优势,并演示其资源推送功能,不过在此之前,同样先简单的介绍在 Nginx 中 HTTP/2.0 相关指令配置。
Nginx HTTP/2 模块指令 在 Nginx 中要完全支持 HTTP/2.0 相关功能,需在编译时启用 --with-http_v2_module 选项,以安装 ngx_http_v2_module 模块,其次必须开启 TLS/SSL 协议,需申请并配置SSL证书(如通过Let's Encrypt、自签证书),ngx_http_v2_module 帮助文档地址 https://nginx.org/en/docs/http/ngx_http_v2_module.html
# 构建脚本 Makefile ./configure --prefix=/usr/ local /nginx --user=nginx --group=nginx --sbin-path=/usr/sbin/nginx --conf-path=/usr/ local /nginx/conf/nginx.conf --pid-path=/usr/ local /nginx/nginx.pid --error-log-path=/var/ log /nginx/logs/error.log --http-log-path=/var/ log /nginx/logs/access.log --lock-path=/var/run/nginx.lock --modules-path=/usr/ local /nginx/modules --with-http_stub_status_module --with-http_realip_module --with-http_ssl_module --with-http_slice_module --with-http_v2_module --with-cc-opt=-O2 --with-compat # 编译安装 make -j$(nproc) && make install
指令模块
http2 指令用于启用 HTTP/2.0 支持,默认情况下是关闭的。
Syntax: http2 on | off; Default: http2 off; Context: http, server This directive appeared in version 1.25.1. # 基础示例 server { listen 443 ssl; # 开启 TLS/SSL 协议,启用 HTTPS 服务。 http2 on; # 启用 HTTP/2.0 支持。 ssl_certificate server.crt; # 指定 SSL 证书文件路径。 ssl_certificate_key server.key; # 指定 SSL 私钥文件路径。 }
资源推送指令,用于配置服务器主动向客户端推送资源。
http2_push 指令用于将请求与对原始请求的响应一起沿着发送(推送)到指定的 uri,使用相对路径也可使用变量,并且可在同一配置级别上指定多个 http2_push 指令,但自版本1.25.1起已过时,建议在头部字段中添加 Link 预加载提示。
Syntax: http2_push uri | off; Default: http2_push off; Context: http, server, location # 示例 http2_push /static/css/main.css; http2_push_preload 指令用于启用或禁用预加载推送,默认情况下是关闭的,启用后需在头部字段中添加 Link 预加载提示,以便浏览器知道哪些资源将被推送,同样自版本 1.25.1 起已过时。
Syntax: http2_push_preload on | off; Default: http2_push_preload off; Context: http, server, location # 示例:若响应头含 Link: </star.css>; rel=preload,则star.css被推送。 http2_push_preload on;
请求接并发与流控制指令,用于配置 HTTP/2.0 连接并发和流控制相关参数。
http2_max_concurrent_pushes 指令用于限制连接中并发推送请求的最大数量,自版本1.25.1起已过时。
Syntax: http2_max_concurrent_pushes number; Default: http2_max_concurrent_pushes 10; Context: http, server http2_max_concurrent_streams 指令用于设置连接中并发HTTP/2流的最大数量,自版本1.25.1起已过时。
Syntax: http2_max_concurrent_pushes number; Default: http2_max_concurrent_pushes 10; Context: http, server http2_max_requests 指令用于设置一个HTTP/2连接可以处理的最大请求数(包括推送请求),超过此数量后,下一个客户端请求将导致连接关闭并需要建立新的连接,自版本1.25.1起已过时,建议使用 keepalive_requests 指令代替。
Syntax: http2_max_requests number; Default: http2_max_requests 1000; Context: http, server http2_chunk_size 指令用于设置响应正文切片的最大块大小, 过低的值会导致更高的开销, 过高的值会由于HOL阻塞而损害优先级。
Syntax: http2_chunk_size size; Default: http2_chunk_size 8k; Context: http, server, location
缓冲区大小设置指令,用于配置 HTTP/2.0 连接缓冲区大小相关参数。
http2_body_preread_size 指令用于设置每个请求主体的缓冲区大小,默认情况下是 16k。
Syntax: http2_body_preread_size size; Default: http2_body_preread_size 64k; Context: http, server http2_max_field_size 指令用于限制经过HPACK压缩的请求标头字段的最大大小,默认情况下是 4k。自版本1.19.7起已过时,建议使用 large_client_header_buffers 指令。
Syntax: http2_max_field_size size; Default: http2_max_field_size 4k; Context: http, server http2_max_header_size 指令用于限制HPACK解压缩后整个请求标头列表的最大大小。对于大多数请求,默认限制应该足够了,自版本1.19.7起已过时,建议使用 large_client_header_buffers 指令。
Syntax: http2_max_header_size size; Default: http2_max_header_size 16k; Context: http, server http2_recv_buffer_size 指令用于设置每个工作进程输入缓冲区的大小。
Syntax: http2_recv_buffer_size size; Default: http2_recv_buffer_size 256k; Context: http
超时控制指令,用于配置 HTTP/2.0 连接超时相关参数。
http2_idle_timeout 指令用于空闲多少时间后关闭连接,自版本1.19.7起已过时,建议使用 keepalive_timeout 指令代替。
Syntax: http2_idle_timeout time; Default: http2_idle_timeout 3m; Context: http, server http2_recv_timeout 指令用于设置接收超时时间,自版本1.19.7起已过时,应该使用 client_header_timeout 指令。
Syntax: http2_recv_timeout time; Default: http2_recv_timeout 30s; Context: http, server 另外,该模块还提供了一个内置变量 $http2 ,可用于检测当前连接是否为 HTTP/2.0 连接,其变量标识符值为:
“h2” for HTTP/2 over TLS, “h2c” for HTTP/2 over cleartext TCP, or an empty string otherwise. 实践演示 步骤 01.作者准备一些静态资源文件和自签证书【参考文章:Nginx | 核心知识150讲之SSL证书签发与HTTPS加密传输学习实践笔记】,以演示其 HTTP/2.0 资源推送功能。
$ cd /usr/local/nginx/html $ tree . . ├── video.html ├── img │ └── bg.png ├── video │ └── 202403192224.mp4 ├── css │ └── style.css ├── js │ └── index.js └── index.html <!-- 其中 index.html 首页,内容如下 --> tee index.html <<' EOF ' < HTML > < HEAD > < meta charset = "UTF-8" > < title > 测试HTTP2.0推送 </ title > </ HEAD > < BODY > < h1 > 测试HTTP2.0推送 </ h2 > < BODY > </ HTML > EOF <!-- 其中创建一个视频播放页面,如下所示: --> tee video.html <<' EOF ' < video id = "myVideo" class = "responsive-video" src = "/videos/202403192224.mp4" poster = "/img/bg.jpg" preload = "metadata" controls playsinline muted loop width = "1280" height = "720" crossorigin = "anonymous" data-setup = '{}' > <!-- 多格式源文件,确保浏览器兼容性 --> <!-- <source src="/videos/sample.mp4" type="video/mp4"> <source src="/videos/sample.webm" type="video/webm"> <source src="/videos/sample.ogv" type="video/ogg"> --> <!-- 字幕/字幕轨道 --> <!-- <track kind="subtitles" src="/videos/captions.vtt" srclang="zh" label="中文"> <track kind="subtitles" src="/videos/captions-en.vtt" srclang="en" label="English"> <track kind="chapters" src="/videos/chapters.vtt" srclang="zh"> --> <!-- 降级方案 --> < p class = "video-fallback" > 您的浏览器不支持 HTML5 视频。 < a href = "/videos/202403192224.mp4" download > 下载视频 </ a > </ p > </ video > EOF
步骤 02.配置 Nginx 启用 HTTP/2.0 支持,并开启资源推送功能,修改完毕后验证配置并重启 Nginx 服务。
tee /usr/ local /nginx/conf.d/server.conf << 'EOF' # 只在连接为 HTTP/2 且支持推送时执行推送 map $http2 $push_allowed { default "" ; "h2" "1" ; } server { # 监听 443 端口,启用 TLS/SSL 协议 listen 443 ssl; # 虚拟主机服务器名称 server_name server.weiyigeek.top; default_type text/html; # 启用 HTTP/2 支持 http2 on; # 日志文件 access_log /var/ log /nginx/server.log main; error_log /var/ log /nginx/server.err.log debug; # SSL 证书文件 ssl_certificate /usr/ local /nginx/certs/server.crt; # ssl_certificate_key /usr/local/nginx/certs/server.key; # 加密的 SSL 证书密钥文件(根据需求选择) ssl_certificate_key /usr/ local /nginx/certs/server_encrypted.key; ssl_password_file /usr/ local /nginx/certs/ssl_password.txt; # 支持的 SSL/TLS 协议版本 ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; # 支持的 SSL/TLS 加密套件 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE:ECDH:AES:HIGH:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:!NULL:!aNULL:!eNULL:!EXPORT:!PSK:!ADH:!DH:!DES:!MD5:!RC4; # SSL 会话缓存 ssl_session_cache shared:SSL:10m; # SSL 会话超时时间 ssl_session_timeout 10m; # 优先使用服务器端支持的加密套件 ssl_prefer_server_ciphers on; # 强制使用 HTTPS 访问 add_header Strict-Transport-Security "max-age=31536000;includeSubDomains;preload" always; # 根目录设置 root /usr/ local /nginx/html; # 缺省文件索引页设置,即访问根目录时默认打开的文件名 index index.html; # 使用 Link 指定推送多个资源 location / { # 推送 css 和 js 文件作为预加载资源 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" ; } # 仅当连接为 HTTP/2 且支持推送时才执行推送 location = /video.html { if ( $push_allowed ) { # 推送 MP4 视频文件 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" ; } } # 特别注意:使用 http2_push、http2_push_preload 指令推送资源已失效,Nginx 1.25.1 及以后已不支持这种方式。 location /old { http2_push /css/style.css; http2_push /res/202403192224.mp4; } } EOF # 验证重载 nginx -t && nginx -s reload nginx: the configuration file /usr/ local /nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/ local /nginx/conf/nginx.conf test is successful nginx: [warn] the "http2_push" directive is obsolete, ignored in /usr/ local /nginx/conf.d/server.conf:77 nginx: [warn] the "http2_push" directive is obsolete, ignored in /usr/ local /nginx/conf.d/server.conf:78 温馨提示:Nginx 1.25.1 及以后版本已废弃 http2_push、http2_push_preload 等指令,不再支持资源推送功能,在配置文件中使用这些指令将会被忽略,一定要使用 add_header Link 方式来实现资源推送。
步骤 03.为了防止各位看友旧版本的 curl 工具不支持 HTTP/2.0 协议,所以这里我们使用 nghttp 命令行工具来测试 Nginx HTTP/2.0 协议,可通过 Github 或者通过包管理器安装,官网地址:https://nghttp2.org/
# 方式1.通过 Github 下载版本进行编译安装 # Ubuntu/Debian sudo apt-get install g++ make binutils autoconf automake \ autotools-dev libtool pkg-config zlib1g-dev libcunit1-dev \ libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \ libc-ares-dev libjemalloc-dev libsystemd-dev cython python3-dev # CentOS/RHEL sudo yum install gcc gcc-c++ make cmake automake autoconf libtool \ pkgconfig zlib-devel openssl-devel libxml2-devel libev-devel \ jansson-devel c-ares-devel python3-devel python3-pip # 下载源码 wget https://github.com/nghttp2/nghttp2/releases/download/v1.68.0/nghttp2-1.68.0.tar.xz # 解压 xz -k -d nghttp2-1.68.0.tar.xz tar -xvf nghttp2-1.68.0.tar # 构建 ./configure -- enable -app # 编译 make -j$(nproc) # 检查产物 ls src/.libs/ # 有时临时文件在这里 deflatehd h2load inflatehd nghttp nghttpd nghttpx # 主要工具包括: # nghttp - HTTP/2 客户端 # nghttpd - HTTP/2 服务器 # h2load - 负载测试工具 # nghttpx - 代理服务器 # 安装 sudo make install # 更新动态链接库缓存 sudo ldconfig /usr/ local /lib # 方式2.通过包管理器安装(版本可能过旧) # redhat 系 yum install nghttp2 # debian 系 apt install nghttp2
weiyigeek.top-nghttp2测速工具图
步骤 04.使用 nghttp 命令行工具测试 Nginx HTTP/2.0 支持情况,
# 访问主页路径 /usr/ local /bin/nghttp -ans https://nghttp2.org ***** Statistics ***** Request timing: responseEnd: the time when last byte of response was received relative to connectEnd requestStart: the time just before first byte of request was sent relative to connectEnd. If '*' is shown, this was pushed by server. process: responseEnd - requestStart code: HTTP status code size: number of bytes received as response body without inflation. URI: request URI see http://www.w3.org/TR/resource-timing/ #processing -modelsorted by 'complete' id responseEnd requestStart process code size request path 1 +731.81ms +73us 731.74ms 200 6K / 3 +1.27s +732.00ms 537.07ms 200 6K /javascripts/modernizr-2.0.js 5 +1.34s +732.01ms 612.92ms 200 8K /javascripts/octopress.js 2 +1.34s * +246.02ms 1.10s 200 38K /stylesheets/screen.css # 访问 / 路径 /usr/ local /bin/nghttp -anv --no-verify https://server.weiyigeek.top/ # 访问 /video.html 路径 /usr/ local /bin/nghttp -anv --no-verify https://server.weiyigeek.top/video.html
weiyigeek.top-使用 nghttp 命令行工具验证图
但经过作者测试,在访问验证 HTTP/2.0 自动推送时,建议通过主流的浏览器(Firefox、Google、Edge)进行访问 /video.html 路径时,可以更加直观的看到资源推送的效果。
weiyigeek.top-使用主流浏览器验证HTTP2.0推送图
温馨提示: 若 curl 版本够新支持 --http2 参数也是可以进行检查 ALPN 协商,例如:
$ curl -V curl 8.4.0 # 查看详细的 HTTP/2 信息 curl -i --http2 https://server.weiyigeek.top/video.html -k HTTP/2 200 server: nginx/1.29.0 date: Sat, 10 Jan 2026 15:20:55 GMT content-type: text/html content-length: 931 last-modified: Sat, 10 Jan 2026 04:51:37 GMT etag: "6961dad9-3a3" expires: Sat, 10 Jan 2026 16:20:55 GMT cache-control: max-age=3600 link: </css/style.css>; as=style; rel=preload, </videos/202403192224.mp4>; as=video; type =video/mp4; rel=preload link: </img/bg.png>; as=image; rel=preload cache-control: public, no-cache accept-ranges: bytes 步骤 05.查看 Nginx 访问日志,可以看到资源推送的效果,由下图可知即使 index.html 中未引入 css / js 文件也将主动推送,另外在 video.html 文件中未引入 css 以及 png 文件也是一并推送的。
weiyigeek.top-利用Nginx 访问日志查看HTTP2.0消息推送图
至此,本文详细介绍了 HTTP/2.0 协议,和 Nginx 中 ngx_http_v2_module 模块指令参数,以及如何开启 HTTP/2.0 支持,并演示了其资源推送功能。
阅读原文:原文链接
该文章在 2026/1/12 10:52:36 编辑过