如何通过配置phpEnv使Nginx支持HTTP2推送,优化PHP性能?
- 内容介绍
- 文章标签
- 相关推荐
本文共计892个文字,预计阅读时间需要4分钟。
确认 Nginx 版本与 http_v2_module 是否可用
phpEnv 自带的 Nginx 通常为 1.18–1.22 区间,但部分精简版会移除 http_v2_module。直接运行:
phpenv\nginx\nginx.exe -V
检查输出中是否含 --with-http_v2_module。若没有,换用官方编译版 Nginx(如 nginx.org 提供的 Windows 二进制包),再替换 phpEnv 中的 nginx.exe 和 conf/ 目录。
注意:http2_push 要求 Nginx ≥ 1.13.9;低于该版本即使加了指令也无效,日志里只报 unknown directive "http2_push"。
立即学习“PHP免费学习笔记(深入)”;
必须走 HTTPS:listen 指令不能拆开写
phpEnv 的 Nginx 默认监听 80 端口、无 SSL,这和 HTTP/2 冲突。你得:
- 用 Let’s Encrypt 或 OpenSSL 生成本地证书(
phpenv\nginx\conf\ssl\下建目录放cert.pem和key.pem) - 在
phpenv\nginx\conf\nginx.conf的server块里,把原来listen 80;改成完整一行:
listen 443 ssl http2;
不是两行:listen 443 ssl; + listen 443 http2; —— 这样 Nginx 会只认第一条,第二条报错或静默丢弃。
同时补全证书路径、TLS 版本和加密套件:
ssl_certificate conf/ssl/cert.pem; ssl_certificate_key conf/ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
http2_push 不是“自动分析 HTML”,必须硬编码路径
即便配好了 HTTPS + HTTP/2,http2_push 也不会扫描你的 PHP 页面去推 CSS/JS。它只在匹配到指定 location 时,按你写的绝对路径发起推送。
例如,你想在访问 /index.php 时推资源,得这样写:
location = /index.php { fastcgi_pass 127.0.0.1:9000; # 其他 fastcgi_param ... http2_push /css/app.css; http2_push /js/main.js; http2_push /fonts/icon.woff2; }
注意三点:
- 路径必须是客户端可直连的 URL 路径(即能通过
https://localhost/css/app.css访问到),不是服务器文件系统路径 - PHP 输出的 HTML 里不能有同名资源的
<link rel="preload">,否则现代浏览器(Chrome 96+、Firefox 97+)会直接忽略推送 - 推送资源需真实存在,否则 Nginx 日志报
open() "/path/to/nginx/html/css/app.css" failed (2: No such file or directory)
实际效果极弱,优先用 Link preload 替代
目前所有主流浏览器已禁用 Server Push 机制。你在 Chrome DevTools 的 Network 面板看到的 h2 协议,不代表 http2_push 生效了——它大概率被浏览器丢弃,且可能增加首字节延迟(TTFB)。
真正可控的做法是在 PHP 中输出响应头:
header('Link: </css/app.css>; as=style; rel=preload'); header('Link: </js/main.js>; as=script; rel=preload');
这个 Link 头兼容 HTTP/1.1 和 HTTP/2,不依赖 Nginx 推送逻辑,浏览器自主决定是否加载、何时加载,出错率低、调试直观。
复杂点在于:PHP 动态页面需要知道当前页面要预加载哪些资源,不能靠 Nginx 静态配置兜底;而这点恰恰是 phpEnv 这类集成环境最不擅长抽象的部分——它没提供资源依赖管理层。
本文共计892个文字,预计阅读时间需要4分钟。
确认 Nginx 版本与 http_v2_module 是否可用
phpEnv 自带的 Nginx 通常为 1.18–1.22 区间,但部分精简版会移除 http_v2_module。直接运行:
phpenv\nginx\nginx.exe -V
检查输出中是否含 --with-http_v2_module。若没有,换用官方编译版 Nginx(如 nginx.org 提供的 Windows 二进制包),再替换 phpEnv 中的 nginx.exe 和 conf/ 目录。
注意:http2_push 要求 Nginx ≥ 1.13.9;低于该版本即使加了指令也无效,日志里只报 unknown directive "http2_push"。
立即学习“PHP免费学习笔记(深入)”;
必须走 HTTPS:listen 指令不能拆开写
phpEnv 的 Nginx 默认监听 80 端口、无 SSL,这和 HTTP/2 冲突。你得:
- 用 Let’s Encrypt 或 OpenSSL 生成本地证书(
phpenv\nginx\conf\ssl\下建目录放cert.pem和key.pem) - 在
phpenv\nginx\conf\nginx.conf的server块里,把原来listen 80;改成完整一行:
listen 443 ssl http2;
不是两行:listen 443 ssl; + listen 443 http2; —— 这样 Nginx 会只认第一条,第二条报错或静默丢弃。
同时补全证书路径、TLS 版本和加密套件:
ssl_certificate conf/ssl/cert.pem; ssl_certificate_key conf/ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
http2_push 不是“自动分析 HTML”,必须硬编码路径
即便配好了 HTTPS + HTTP/2,http2_push 也不会扫描你的 PHP 页面去推 CSS/JS。它只在匹配到指定 location 时,按你写的绝对路径发起推送。
例如,你想在访问 /index.php 时推资源,得这样写:
location = /index.php { fastcgi_pass 127.0.0.1:9000; # 其他 fastcgi_param ... http2_push /css/app.css; http2_push /js/main.js; http2_push /fonts/icon.woff2; }
注意三点:
- 路径必须是客户端可直连的 URL 路径(即能通过
https://localhost/css/app.css访问到),不是服务器文件系统路径 - PHP 输出的 HTML 里不能有同名资源的
<link rel="preload">,否则现代浏览器(Chrome 96+、Firefox 97+)会直接忽略推送 - 推送资源需真实存在,否则 Nginx 日志报
open() "/path/to/nginx/html/css/app.css" failed (2: No such file or directory)
实际效果极弱,优先用 Link preload 替代
目前所有主流浏览器已禁用 Server Push 机制。你在 Chrome DevTools 的 Network 面板看到的 h2 协议,不代表 http2_push 生效了——它大概率被浏览器丢弃,且可能增加首字节延迟(TTFB)。
真正可控的做法是在 PHP 中输出响应头:
header('Link: </css/app.css>; as=style; rel=preload'); header('Link: </js/main.js>; as=script; rel=preload');
这个 Link 头兼容 HTTP/1.1 和 HTTP/2,不依赖 Nginx 推送逻辑,浏览器自主决定是否加载、何时加载,出错率低、调试直观。
复杂点在于:PHP 动态页面需要知道当前页面要预加载哪些资源,不能靠 Nginx 静态配置兜底;而这点恰恰是 phpEnv 这类集成环境最不擅长抽象的部分——它没提供资源依赖管理层。

