- Published on
Content-Encoding: zstd — Safari 26.3 补齐三大引擎,下一步是 RFC 9842 压缩字典
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 引言 — 最后一块拼图补上了
- 支持矩阵 — zstd 和压缩字典不是一回事
- zstd 实际能带来什么 — 数字要带着条件看
- 服务器端依旧不对称
- 下一步 — RFC 9842 压缩字典传输
- 实测数据 — 静态流程与动态流程
- 字典不是答案的时候
- 实务判断
- 结语
- 参考资料
引言 — 最后一块拼图补上了
2026年2月11日发布的 Safari 26.3 发行说明里有这样一句话。原文照搬 — "Added support for Zstandard content encoding in Safari 26.3 for iOS, iPadOS, visionOS, and macOS 26.3."(Apple 发行说明)
这一句话改变了局面。Content-Encoding: zstd 此前已经被 Chrome 123(2024年3月)、Firefox 126(2024年5月)支持,剩下的最大一块就是 Safari。现在三大浏览器引擎(Blink、Gecko、WebKit)全都能接收用 zstd 压缩的 HTTP 响应了。HTTP 传输压缩的标准选项,继 gzip、brotli 之后增加到三个,可以说实质上完成了。
当然要先把注意事项写在前面。据WebKit 博客,Safari 26.3 的 zstd 在 iOS/iPadOS/visionOS 26.3 和 macOS Tahoe 26.3 上生效,在运行于较旧 macOS 版本上的 Safari 26.3 中不生效(依赖系统网络栈)。因此caniuse 的统计也把 Safari 26.3 归类为部分支持,并附注「需要 macOS 26.3 以上」——按撰文时的查询数据,全面支持的浏览器份额约为 79.5%,部分支持约为 2.1%。
不过,采用本身的风险很低。压缩由 Accept-Encoding 协商决定,收不到 zstd 的客户端会自动回退到 brotli 或 gzip。打开它不会破坏任何东西,不打开也就没有额外收益。
支持矩阵 — zstd 和压缩字典不是一回事
按MDN 的浏览器兼容性数据整理如下。
| 功能 | Chrome | Firefox | Safari |
|---|---|---|---|
Content-Encoding: zstd | 123 (2024-03) | 126 (2024-05) | 26.3 (2026-02) |
dcb / dcz(压缩字典,RFC 9842) | 130 (2024-10) | 不支持 | 不支持 |
上面一行是这次补齐的故事,下面一行是本文后半部分要讲的故事。压缩字典传输已于 2025 年 9 月以 RFC 9842 的形式发布(作者是 Google 的 P. Meenan 和 Shopify 的 Y. Weiss),但目前只有 Chromium 系浏览器出货。不过 Mozilla 已表明官方立场为 positive,WebKit 也表明了support,所以并不是因为反对而卡住。
zstd 实际能带来什么 — 数字要带着条件看
照搬 zstd 项目在 README 中公开的自测基准,条件原样保留:Core i7-9700K @ 4.9GHz、Ubuntu 24.04、gcc 14.2.0、lzbench(内存内)、Silesia 语料库——也就是说这是项目自己的测量,是不经过磁盘和网络的纯 CPU 吞吐数字。
| 压缩器(1 级系列) | 压缩率 | 压缩速度 | 解压速度 |
|---|---|---|---|
| zstd 1.5.7 -1 | 2.896 | 510 MB/s | 1550 MB/s |
| brotli 1.1.0 -1 | 2.883 | 290 MB/s | 425 MB/s |
| zlib 1.3.1 -1 | 2.743 | 105 MB/s | 390 MB/s |
这张表要看的不是排名,而是差距的性质。在同样的「快速档位」区间里,zstd 比 zlib 压缩快约 5 倍、解压快约 4 倍,压缩率反而更高。所以 zstd 的常见用武之地是动态响应的 on-the-fly 压缩——WebKit 博客的介绍框架也正是如此。brotli 通常用在构建期把静态资产以最高级别预先压缩好,而需要实时压缩的 API 响应、HTML,则是 zstd 在 CPU 预算上更划算。顺带一提,这张表是以 1 级为准的,所以「相对 brotli 最高级别的压缩率」之类的说法在这里得不出——如果好奇算法内部(LZ77、ANS、Huffman),可以看压缩算法深度剖析一篇。
在 HTTP 之外,这已经是验证过的替换了。Discord 把网关(WebSocket)压缩从 zlib 流式换成了 zstd 流式,并公开了自己的测量数据:MESSAGE_CREATE 负载的压缩率从 6 左右升到接近 10,平均大小从 270 字节降到 166 字节(2024 年上线)。原文明确写到,他们所说的「网关带宽减少约 40%」并非 zstd 单独的功劳,而是与另一项 passive sessions 优化叠加后的数字。
顺带说一下库本身的发布状态——最新版本是 v1.5.7(2025-02-19),dev 分支的 CHANGELOG 里已经准备好了 v1.6.0 的条目(默认关闭对旧版格式的支持),但截至 2026 年 7 月 17 日,既没有打 tag,也没有 GitHub release。
服务器端依旧不对称
浏览器全都能接收了,并不代表结束。发送端的地形是这样的(截至 2026 年 7 月,均已核对各项目的官方文档、变更日志)。
- nginx — 没有官方 zstd 模块。官方文档的模块列表里没有出现 zstd,要用就得自己构建第三方模块。
- Apache httpd — 2.4.x 系列的 CHANGES 里没有 zstd 条目。官方支持到 mod_brotli 为止。
- Caddy —
encode指令支持 zstd。 - Node.js — 从 v23.8.0(2025-02-13)起,
node:zlib加入了 zstd 压缩/解压 API。可以在应用层直接处理。 - CDN — Cloudflare 在所有套餐中都支持 Zstandard,Free 套餐的默认压缩方式就是 Zstandard(brotli、zstd 都要求响应体至少 50 字节)。
总结一下,如果源站是 nginx/httpd,今天最短的路径就是在 CDN 上打开它。两大主流 Web 服务器都没有官方模块,这是当前 zstd 落地的实际瓶颈,「浏览器支持已完成」与「服务器生态已完成」之间的时间差,正是这个话题目前所处的位置。
下一步 — RFC 9842 压缩字典传输
如果说补齐 zstd 支持是第一幕,第二幕就是字典(dictionary)压缩。想法很简单。压缩算法靠参照「已经见过的数据」来压缩接下来的数据,而浏览器手上其实已经握着不少东西——昨天收到的 JS 包、同一网站的其他 HTML。把它当作字典用,实际上就只需要传输差量(delta)了。
把 RFC 9842 定义的流程画成一个概念示例,是这样的。
# 1) 首次访问 - 服务器告知把这个响应注册为字典
GET /js/app.v133.js
<- 200 OK
<- Content-Encoding: br
<- Use-As-Dictionary: match="/js/app*.js"
# 2) 再次访问 - 浏览器公布自己持有的字典的哈希
GET /js/app.v134.js
-> Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
-> Accept-Encoding: gzip, br, zstd, dcb, dcz
# 3) 服务器只发送用该字典压缩过的差量
<- 200 OK
<- Content-Encoding: dcb
也有通过 <link rel="compression-dictionary"> 单独下发字典资源的路径。新增的内容编码有两种:dcb 是 4 字节魔数加上字典的 SHA-256 哈希(32 字节),后面跟一个 Shared Brotli 流的格式(客户端有义务能解压最大 16MB 的窗口);dcz 是被设计成 zstd skippable frame 的格式——40 字节头部后面跟着应用了字典的 zstd 流——客户端需要支持的窗口大小是 8MB 与字典大小的 1.25 倍之中较大者(上限 128MB)。如果响应可缓存,Vary: accept-encoding, available-dictionary 是必需的——为的是防止字典被错误地提供给其他客户端。细节在 RFC 9842 第 4、5 章。
实测数据 — 静态流程与动态流程
数字要分两类来看。下面分别附上出处和条件。
静态流程(把旧版本当字典)。 基准是 RFC 共同作者 Meenan 公开的测试合集。这是作者自己的测量,条件是 brotli CLI 5 级、「字典 = 同一资源的旧版本」。
- YouTube 桌面播放器 JS(10MB,未压缩):单独用 brotli 能压到 1.8MB → 用两个月前的版本作字典,压到 384KB(减少 78%)。如果按周发布的节奏,172KB(减少 90%)。
- CNN 头部包(278KB):单独用 brotli 能压到 90KB → 用一年前的版本作字典,压到 2KB(减少 98%)。
- 同一份文档里也写到,像 Wikipedia 这种以文本为主、本来就压缩得很好的页面,改善幅度小得多。
动态流程(路径专用的定制字典)。 这里有真实上线的数字。Google 搜索在搜索结果页 HTML 上部署了共享的 brotli 字典,并把结果公开在 Chrome 博客上(2025-05-14,厂商自测)。在用代表性样本生成字典、并用自动化流水线一天更新好几次的条件下——
- 以全体 Chrome 用户为基准,HTML 负载平均减少 23%。这个平均值里包含了还没有字典的首次访问用户。
- 只看字典命中的响应,减少幅度接近 50%。
- 从体感指标看,LCP 整体改善 1.7%,在高延迟网络上最多改善 9%。
我觉得最后这一行,是这篇文章里最诚实的数字。就算传输字节数减少了几十个百分点,全世界优化程度数一数二的页面,LCP 也只改善了 1.7%。压缩节省率和体感速度并不等价——尤其是在带宽不是瓶颈的环境里。反过来,在高延迟、低带宽环境下最多 9% 这一点,也说明这项技术的价值会随用户分布大幅波动。
字典不是答案的时候
为了平衡一下,也讲一个失败案例。Discord 在上面那次 zstd 迁移过程中,也尝试过字典——用 12 万条匿名化消息,分别训练了 JSON 用和 ETF 用两个字典。离线评估中看起来很有希望,小型负载从 636 字节降到了 187 字节(不用字典是 466 字节),但在生产环境里结果好坏参半。2.5MB 的 READY 负载即便用了字典,也只多减少了约 600 字节,而 MESSAGE_CREATE 反而变差了。结论是放弃字典——他们的总结是「字典带来的小幅压缩改善,抵不上给网关和客户端增加的复杂度」。
原因是结构性的。Discord 的连接一直保持着流式压缩上下文,只要连接不断,压缩器早就已经在「从过去的数据里学习」了。字典能帮上忙的,只有流最初的几 KB。zstd 项目自己的文档也是这么说的——字典带来的收益集中在小数据最初的几 KB,不存在万能字典,得按数据类型分别训练。
HTTP 侧的字典压缩(RFC 9842)也有它自己的成本。
- 运维流水线。 Google 那个案例的前提,是一天多次重新生成、重新部署字典的自动化。内容变了而字典没跟上,收益就会缩水。构建、服务路径里要多加上字典的版本管理。
- 隐私规定。 因为字典哈希可能被滥用成追踪 cookie,RFC 第 10 章要求客户端把字典当作 cookie 同等对待——采用 cookie 级别(或更严格)的分区,清除 cookie 时也要一并清除字典。也就是说,字典的命中率不可能超过 cookie 的生命周期。
- 安全约束。 混合来源压缩攻击(CRIME/BREACH 系列,RFC 7457)的考量,同样适用于字典——字典里不能放用户数据(Discord 也对训练数据做了匿名化),字典匹配限制在 same-origin,跨源使用则必须通过 CORS。
- 浏览器覆盖率。 再强调一次,目前只有 Chromium 系。Firefox/Safari 用户还是得继续维护普通压缩路径,所以字典压缩是「额外的一条流水线」,不是替代品。
实务判断
现在就该打开的 — Content-Encoding: zstd。 有协商式回退兜底,风险很低,浏览器覆盖率随着这次 Safari 26.3 基本补齐了。如果在 CDN 后面,那就是一个配置开关的事。要是想在源站直接做,nginx/httpd 没有官方模块是现实的障碍,可以在 Caddy、Node 应用层、CDN 之中挑一条适合自己技术栈的路径。核心用武之地是动态(on-the-fly)响应,静态资产的预压缩沿用现有的 brotli 流水线也没问题。
算完账再决定的 — dcb/dcz。 如果服务的回访比例高、JS 包体积大、发布频繁,光靠 Chromium 那部分份额带来的节省,账也可能算得过来。就像上面的实测数据那样,差量传输带来的节省是数量级上的差别。但前提是团队要能承担字典生成、版本管理流水线,以及双重服务路径,而且要用自家服务的体感指标(比如 LCP)而不是节省的字节数来验证收益——就连 Google,整体 LCP 改善也才 1.7%。
不要做的事。 流量小、或者用户很少回访的网站一上来就先搭字典基础设施。给已经有流式压缩上下文的定制协议硬塞字典(Discord 的教训)。还有,把厂商公布的节省率直接等同于自家服务的性能提升。
结语
归纳一下。随着 Safari 26.3(2026-02-11)的到来,Content-Encoding: zstd 在浏览器这一侧的拼图补齐了,剩下不对称的是服务器生态(两大主流 Web 服务器都没有官方模块)。下一步的 RFC 9842 字典压缩,标准化(2025-09)和实际部署验证(Google 搜索,厂商自测平均减少 23% 的负载)都已经做完,但浏览器目前仍只有 Chromium 支持,运维成本和隐私规定都是真实存在的约束。zstd 今天就可以打开,字典则要先用自己的流量算一笔账。压缩率是手段,指标永远在用户那一侧。
参考资料
- Safari 26.3 Release Notes — Apple Developer
- WebKit Features in Safari 26.3 — webkit.org
- RFC 9842 — Compression Dictionary Transport
- Content-Encoding — MDN(浏览器兼容性表)
- zstd (Zstandard) content-encoding — caniuse
- facebook/zstd — Benchmarks(项目自测)
- Compression dictionary transport examples — WICG(作者自测)
- How Google Search made their results pages 23% smaller — Chrome for Developers(厂商自测)
- How Discord Reduced Websocket Traffic by 40% — Discord(厂商自测)
- Zstd Content-Encoding — Chrome Platform Status
- Compression dictionary transport — Chrome Platform Status
- Mozilla standards-positions #771 (positive) · WebKit standards-positions #160 (support)
- Node.js v23.8.0 — node:zlib zstd 支持
- Cloudflare compression 文档 · Caddy encode 指令
- 压缩算法深度剖析 — LZ77, zstd, brotli, ANS, Huffman(相关文章)