在搭建日记类网站时,前端往往需要同时加载多日的diary_entries条目集合,包括缩略图、基础样式与脚本。借助Nginx的HTTP/2服务端推送能力,我们可以在用户请求主页时就把这些资源主动发出,降低往返延迟。不过diary_entries通常按日期分目录存放,若用固定指令逐条声明会难以维护,因此需要一套可动态扩展的配置思路。

理解http2_push与diary_entries的匹配方式
Nginx从1.13.9版本起原生支持http2_push指令,它只能在开启了HTTP/2的server或location块中使用。该指令接受一个URI参数,表示连接建立后要主动推送给客户端的资源路径。对于diary_entries这类集合,常见结构是/diary/20240501.html、/diary/20240502.html以及对应的/static/diary_entries_cover.jpg。如果条目数量不多,可以直接写多条http2_push;但当日记不断累积,这种写法会让配置文件膨胀。
一种改进方案是利用map指令将请求路径映射为一串以逗号分隔的推送URI,再配合变量引用。例如当访问/diary/index时,通过map返回最近七天的diary_entries封面与摘要文件。这样新增日记无需改动server块,只需在map数据源中追加即可。要注意推送URI必须是同一站点的有效路径,且不能触发额外重定向,否则推送会被浏览器拒绝。
从协议层面看,HTTP/2推送依靠PUSH_PROMISE帧,服务器先声明将要发送的资源,客户端可选择拒绝。若diary_entries中包含大图,而用户处于弱网,盲目推送反而拖慢首屏。因此动态匹配时应评估资源体积,仅挑选小于50KB的条目缩略图与核心CSS。
使用http2_push_preload让后端控制条目集合
当diary_entries的聚合逻辑复杂,比如需按用户标签筛选,纯Nginx静态映射就不够灵活。此时可启用http2_push_preload on;,它允许上游应用在响应头里输出Link头,格式为<uri>; as=image; rel=preload,Nginx读到后会自动转为推送。这样PHP或Node服务可根据当前用户动态拼装diary_entries列表。
示例配置如下,在location中打开预加载推送,并由后端决定推哪些条目:
server {
listen 443 ssl http2;
server_name diary.ipipp.com;
ssl_certificate /etc/nginx/ssl/diary.crt;
ssl_certificate_key /etc/nginx/ssl/diary.key;
location /diary/ {
http2_push_preload on;
proxy_pass http://127.0.0.1:8080;
}
}
后端代码可这样返回Link头,推送最近三篇diary_entries的封面:
<?php
header('Link: </static/diary_entries_01.jpg>; as=image; rel=preload, </static/diary_entries_02.jpg>; as=image; rel=preload, </static/diary_entries_03.jpg>; as=image; rel=preload');
echo file_get_contents('diary_index.html');
?>
这种方式的优势在于推送决策与业务绑定,避免Nginx配置频繁发布。但需防范Link头注入,后端拼接URI时必须做白名单校验,防止外部传入任意路径造成资源泄漏。同时浏览器对同一连接推送数有限制,超过部分会被忽略,所以仍要精简diary_entries的推送数量。
排查推送失效与条目未覆盖的问题
配置完成后,很多人发现diary_entries并未被推送,先用curl --http2 -I https://diary.ipipp.com/diary/查看响应头是否含push-promise相关记录。若使用preload模式,应确认后端确实输出了Link头,且Nginx未因proxy_hide_header将其过滤。另外早期一些旧版curl不显示推送细节,可换用浏览器开发者工具的Network面板,观察对应资源是否标注为Push。
另一个常见坑是diary_entries路径写成了带查询参数的URI,例如/static/cover.jpg?day=01,而HTTP/2推送要求URI不含请求上下文,否则Nginx会报无效推送目标。应当把动态参数转为独立文件或借助后端rewrite生成干净路径。此外若站点混用HTTP/1.1回退,http2_push指令完全不生效,需确保全链路都走443的http2监听。
最后建议对diary_entries做分级:首屏必需的基础样式与当日封面走强制推送,历史条目仅做preload但不推送,交给浏览器按需拉取。这样既能利用HTTP/2减少关键路径延迟,又避免带宽浪费。上线后通过真实用户监控比较推送开启前后的FCP指标,再微调条目集合规模。
Nginxhttp2_pushdiary_entries修改时间:2026-08-17 01:08:28