Nginx从1.13.9版本开始支持HTTP/2 Server Push,通过http2_push指令可以让服务器在发送主资源时主动推送关联的CSS、JavaScript等静态文件,减少一次网络往返。常见配置资料只给出最简单的示例,却没有说明reload之后为什么有时不生效。其实这并不是nginx -s reload没有执行成功,而是重载后的新配置只会作用于新建的HTTP/2连接,已经建立的长连接依然沿用旧配置。下面先解释工作机制,再结合具体配置和验证步骤说明如何正确重载并排查问题。

HTTP/2 Server Push的工作前提
HTTP/2是二进制分帧协议,Server Push是其中一项扩展能力,但它并不是在任意连接上都能使用。Nginx启用HTTP/2必须要基于TLS加密连接,也就是监听端口需要明确写出listen 443 ssl http2。如果只配置了listen 80,或者443端口只写了ssl而没有http2,客户端和服务器之间就协商不出h2协议,后续的推送自然无从谈起。
另一个前提是Nginx编译时必须包含ngx_http_v2_module模块。可以通过执行nginx -V查看编译参数,如果输出中没有--with-http_v2_module,就需要重新编译或更换支持HTTP/2的安装包。现代浏览器基本都支持HTTP/2,但前提是连接协商成功,因此TLS证书必须有效且被客户端信任,否则握手阶段就会失败,连正常访问都会受影响。
还需要注意推送资源的同源策略。Nginx的Server Push只能推送当前响应来源下的资源,不能跨域推送其他站点或CDN上的文件。如果反向代理后面还有源站,而SSL终止在中间层设备上,那么Nginx可能无法直接控制HTTP/2帧,这也会导致配置了http2_push却完全不生效。
http2_push与http2_push_preload配置详解
Nginx提供了两种配置Server Push的方式。第一种是静态指定推送资源,在server或location块中使用http2_push指令,明确写出要推送的资源路径。下面是一个典型示例:
server {
listen 443 ssl http2;
server_name ippipp.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
root /var/www/html;
location / {
http2_push /css/style.css;
http2_push /js/app.js;
}
}
示例中,当用户请求/对应的主文档时,Nginx会同时推送/css/style.css和/js/app.js。路径必须以斜杠开头,并且需要与实际HTML中引用的路径完全一致,否则浏览器可能因为资源路径不匹配而忽略推送。如果资源带有版本号,也要确保推送路径包含版本号,避免出现推送资源被浏览器当作旧缓存处理的情况。
第二种方式是动态读取响应头中的Link字段,配合http2_push_preload指令自动推送。配置写法如下:
location / {
http2_push_preload on;
add_header Link "</css/style.css>; rel=preload; as=style";
}
这里add_header会给响应添加一个Link头,Nginx解析到其中带有rel=preload的资源后,会根据http2_push_preload on的配置自动发送PUSH_PROMISE帧。需要注意add_header的继承机制:如果一个请求同时命中多个location层级,只有最精确匹配的location中的add_header会最终生效,父级配置可能被覆盖。因此建议把add_header和http2_push_preload放在同一个处理实际请求的location块中。
两种方式可以混合使用,但不要对同一个资源重复推送,否则会消耗额外的连接窗口。此外,http2_push指令可以出现在http、server和location三个层级中,但最终生效与否取决于实际处理请求的location。如果只在server块中写了http2_push /style.css,而请求并没有匹配到包含该指令的location,推送很可能不会发生。为了明确可控,建议把http2_push放在实际响应主文档的location块内。
reload重载机制及不生效的常见原因
nginx -s reload实际是向Nginx的master进程发送HUP信号。master进程收到信号后会重新读取并解析配置文件,确认语法无误后启动新的worker进程处理新建连接,而旧的worker进程会等待已有连接完全关闭后再退出。这个过程不会中断正在处理的请求,但也意味着已经建立的HTTP/2连接不会应用新配置。当你修改配置后直接刷新浏览器页面,浏览器通常会复用之前的HTTP/2连接,此时推送行为仍然由旧配置决定,所以看起来像是reload没有生效。
验证推送效果时,必须强制浏览器新建连接。可以打开无痕窗口、关闭浏览器后重新启动,或者使用curl --http2命令发起全新握手。如果使用Chrome开发者工具,可以在Network面板中查看请求的Protocol列是否显示为h2,以及Initiator列是否显示为Push / Other。对于更底层的排查,可以使用nghttp -ans https://ippipp.com观察是否收到PUSH_PROMISE帧。
配置语法错误是另一个高频原因。执行nginx -s reload后如果直接提示失败,需要先运行nginx -t检查配置。常见的报错包括http2_push指令不存在、参数数量错误或指令位置不正确。如果Nginx版本低于1.13.9,或者编译时没有http_v2_module,就会出现未知指令的错误。此时需要先升级或重新编译Nginx,再配置推送功能。
证书与端口配置错误同样会导致HTTP/2协商失败。只写listen 443 ssl的情况下,Nginx虽然能处理TLS,但可能只协商出HTTP/1.1。正确写法是listen 443 ssl http2,如果需要同时监听IPv6,可以再加一行listen [::]:443 ssl http2。多个server块场景下,还要确认当前请求实际命中的是哪个server块,避免把推送配置放到了默认站点而测试域名走了另一个配置文件。
完整排查清单与优化建议
为了快速定位http2_push重载后不生效的问题,可以按照下面的清单逐项检查:
- 执行
nginx -V确认HTTP/2模块已编译 - 监听端口配置中包含
http2参数 - TLS证书有效且客户端信任
http2_push路径与HTML引用完全一致- 使用
nginx -t检查语法后再执行reload - 测试时强制新建连接,避免复用旧的长连接
- 使用开发者工具查看Protocol和Initiator字段
http2_push_preload需要配合Link响应头- 避免在
server和location中重复配置冲突 - 按需调整
http2_max_concurrent_pushes限制
在性能优化层面,Server Push虽然能降低首屏延迟,但滥用会适得其反。如果推送的资源浏览器本地已有缓存,或者推送过多小文件占用连接窗口,反而会增加页面加载时间。比较稳妥的做法是使用http2_push_preload结合服务端动态生成的Link头,只推送当前请求真正需要的资源。对于静态公共资源,可以配合版本化URL和长缓存策略,减少重复推送。而http2_push指令适合固定资源列表,但不具备根据请求头做复杂判断的能力。
还需要了解的是,HTTP/2 Server Push在后续的HTTP/3协议中已经被移除,未来如果迁移到HTTP/3,需要改用103 Early Hints或其他预加载机制。但在当前HTTP/2仍然是主流的情况下,http2_push依然是一个有效的优化手段。只要理解了reload只影响新建连接、推送依赖HTTP/2协议协商和正确的作用域配置,大多数看似失效的场景都能快速定位并解决。
Nginx HTTP/2http2_pushreload配置修改时间:2026-08-24 03:15:51