用了Server Push反而加载更慢怎么办?
我给网站配置了HTTP/2 Server Push推送关键CSS和JS,但发现页面加载时间反而比之前多了200ms,这是为什么呢?
尝试过在nginx里这样配置:
http2_push_preload on;
add_header Link "</code><code class="language-html">/styles.css</code><code class="language-bash">;rel=preload;as=style" always;
结果控制台显示资源重复加载,而且 waterfall里看到push的资源和常规请求同时在走,感觉浪费了带宽。
难道Server Push不是应该让服务器主动推送资源吗?怎么会出现这种矛盾情况?
你用的是 add_header Link 来做 preload,但 http2_push_preload on 的作用是让 Nginx 把 preload 的资源主动 Push 下去。现在你手动加了 preload,相当于告诉浏览器「我要 preload」,但服务器也 Push 了一份,于是两边都发了。控制台看到重复加载、waterfall 里看到两个请求,就是这个原因。本质上是 Push 和 preload 冲突了。
解决方法很简单:要么让服务器 Push,要么让浏览器 preload,选一个就行。如果你想用 Server Push,就去掉 add_header Link 这行,改用 http2_push 指令指定要推的资源。比如:
location = /index.html {
http2_push /styles.css;
http2_push /main.js;
}
这样 Nginx 才会真正主动推送,而不是依赖 Link 头。另外注意 Server Push 只对 HTTP/2 有效,确保你访问是走 HTTPS 的。
Server Push 的好处是减少请求往返,但如果 Push 的资源浏览器已经缓存了,它还是会接收一遍,造成带宽浪费。所以建议只 Push 首屏关键资源,并且配合 ETag 或 Last-Modified 做缓存验证。
问题出在你只加了Link头,没真正指定要推送的资源。试试这个:
location / {
http2_push /styles.css;
http2_push /script.js;
}
Push资源数量控制在3-4个关键文件,Push太多反而拖慢页面。用Chrome DevTools的Network面板观察Push状态,看是否出现"(Push)"标识。
另外,确保浏览器没通过Etag或Last-Modified验证过期资源。加个Cache-Control试试:
add_header Cache-Control "max-age=31536000, immutable" always;
这样能防止浏览器重复请求Push过的资源。搞定。