资讯文章 资讯 · NEWS
103 Early Hints、Brotli、HTTP/2:目录站在传输层还能抠出多少时间
2026-10-22 约 1,891 字 预计阅读 5 分钟 yiyunkj
1
目录站的性能优化做到一定程度,会发现剩下的时间不花在图片上,也不花在 JS 上,而是花在等上——等服务器把页面拼出来,等第一个字节到,等连接建立。这一层叫传输层,改动通常不大,收益也不小。

图片来源:网络,版权归原作者所有,侵权请联系删除
103 Early Hints:把等待时间用起来
服务器收到请求到返回完整 HTML 之间,有一段"思考时间":查数据库、拼模板、算排序。这段时间浏览器是空的,什么也做不了。Early Hints 就是让服务器先丢一个 103 响应回去,告诉浏览器"这些东西待会儿肯定要用,先去拿"。
HTTP/2 103
Link: </static/main.css>; rel=preload; as=style
Link: </static/app.js>; rel=preload; as=script
HTTP/2 200
Content-Type: text/html
...
浏览器收到 103 就开始拉 CSS 和 JS,等真正的 HTML 到达时,样式表已经在路上了。
几点要知道的:
- Chrome 从 103 版本起支持,只支持
preload和preconnect两种提示,prefetch不支持 - 只对导航请求(主文档)生效
- 如果最终响应是跨源重定向,Chrome 会把通过 Early Hints 拿到的资源丢弃
- 服务端支持:Apache 走 mod_http2、H2O 原生支持、Nginx 需要模块、Node 从 18.11 起支持
- 嫌麻烦就用 CDN,Cloudflare、Fastly 都做成了开关
Cloudflare 公开过数据:早期实验中页面加载改善最高到 30%,Shopify 在黑五期间的实测是 LCP 中位数快了 500 毫秒以上。目录站的条目页和分类页都是动态拼的,正好是 Early Hints 最适合的场景。
有个坑别踩:提示出去的资源必须在最终 HTML 里真的用上。提示了 main.css 结果页面用的是别的,等于白浪费一次请求。
顺带提一句 HTTP/2 Push
如果你以前配过 Push,可以停了。Chrome 的实测数据是 Push 在全网范围内总体是负收益——服务器很难判断浏览器缓存里已经有什么,经常推重复的东西,带宽反而浪费。现在主流浏览器都已移除支持。
Brotli:比 gzip 再小一档
Brotli 是 Google 出的压缩算法,对 HTML、CSS、JS 这类文本,通常比 gzip 小 15%~25%。原因之一是它内置了一份 Web 常用字符串字典,HTML 标签、CSS 属性、JS 关键字这些重复出现的片段不用逐字描述。
配置要点:
| 项目 | 建议 |
|---|---|
| 静态资源 | 构建时预压,等级 11 |
| 动态响应 | 等级 4~6,或直接用 gzip |
| 不要压 | 图片、WOFF2 字体、视频、zip(已经压过) |
| 必须配 | Vary: Accept-Encoding |
两个限制记一下:Brotli 只在 HTTPS 下被浏览器声明支持;等级 11 的压缩速度很慢,动态内容每请求压一次会拖慢 TTFB,所以动态内容要么降级,要么用 gzip。
浏览器支持率现在在 96% 以上,剩下的自动回落 gzip,服务端同时开着就行,不用做取舍。Nginx 的写法:
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
HTTP/2 之后该停掉的旧优化
很多 2015 年之前的优化套路,在 HTTP/2 多路复用之后变成了负优化。如果你还在做,可以停了:
- 域名分片。当年为了突破浏览器同域并发数限制,把资源分散到 cdn1、cdn2、cdn3。HTTP/2 单连接就能并发,分片反而多了 DNS 查询和 TLS 握手
- CSS/JS 全量内联。内联是为了省请求,但 HTTP/2 下一个请求的成本低得多,而内联会让缓存失效范围变大。只有真正阻塞首屏的关键 CSS 值得内联
- 图标雪碧图。合成一张大图减少了请求数,但代价是每次改一个图标整张图缓存全失效。HTTP/2 下分别请求更划算
不过图标这件事在目录站上要另说。一页几百个站点小图标,就算 HTTP/2 能并发,几百个请求仍然不是零成本。这种情况更好的做法是 SVG sprite 加 <use> 引用,或者用图标字体,把请求压到一两个。
怎么判断该做哪个
看 TTFB。如果 TTFB 超过 600ms 且页面是动态生成的,先上 Early Hints,它直接对冲的就是这段等待。如果 TTFB 正常但传输体积大,看 Content-Encoding 响应头有没有 br,没有就开 Brotli。如果两者都正常,但 PageSpeed 还在提示"避免 DOM 规模过大",那是页面结构的问题,跟传输层没关系了。