发布时间:2024 年 3 月 6 日
数据压缩是一种经过时间考验的性能优化技术,可减小符合条件的网页资源的大小。在一段时间内,常见的做法是主要在 Web 服务器上使用 gzip 来压缩常见的基于文本的网页资源(例如 HTML、CSS 和 JavaScript 文件),并将它们发送到客户端,以便在客户端进行解压缩。这样一来,资源加载时间会缩短,而不会影响网页的预期行为。
虽然 gzip 本身非常有效,但近年来,Web 上的压缩技术又有了进一步的改进。2016 年,Chrome 中发布了 Brotli 算法,为符合条件的资源提供了总体上更好的压缩率。到 2017 年底,所有现代浏览器都支持 Brotli,并且对它的服务器支持开始变得更加广泛。最近,Chrome 又发布了 ZStandard 压缩。
不过,工作并没有就此止步!Chrome 团队一直在努力使共享字典可在 Web 上使用,现在 Brotli 和 ZStandard 都有了源试用。共享字典可以补充 Brotli 和 ZStandard 压缩,为经常发布更新代码的网站提供大幅更高的压缩率,并且在某些情况下,可以提供 90% 或更高的压缩率 。本文将详细介绍共享字典的工作原理,以及如何注册源试用以在您的网站上使用 Brotli 和 ZStandard。您还可以观看此视频:
共享字典说明
压缩是指在输入中查找冗余序列,并使用该信息创建小得多的输出,该输出稍后可以反转。压缩在 Web 上效果很好,因为它能大幅缩短资源加载时间。Brotli 和 ZStandard 都可以通过使用 压缩字典 来进一步提高其有效性,压缩字典是这些算法在压缩期间可以使用的其他模式的集合。事实上,Brotli 的高效率在一定程度上是通过使用内部字典实现的。
不过,Brotli 和 ZStandard 可以使用 自定义 用户整理的字典,其中包含特定于特定资源的模式。实际上,自定义字典是一个外部文件,可以应用于任何输入。字典可以非常特定于应用的生产代码,或者实际上是任何内容。给定字典对其输入的适用性可能会对整体压缩效率产生很大影响。与输入内容高度相似的字典将产生比内容通用或不相似的字典更高的压缩率。
下面是一个示例,说明了自定义压缩字典的有效性:假设您的网站使用 Angular 框架,而您当前使用的版本是 1.7.9 版。此版本的 Angular 框架大约为 172 KiB(未压缩)。使用 Brotli 的默认设置进行压缩后,其大小约为 53 KiB。这产生了近 70% 的压缩率。不过,假设您决定稍后升级到 Angular 1.8.3。鉴于此版本的 Angular 的大小与 1.7.9 版大致相同,您可以预期与之前版本大致相同的压缩率。
在这种情况下,自定义字典可以通过使用称为 增量压缩 的过程来派上用场,即可以使用资源的先前版本的字典来压缩较新版本。使用前面的示例,如果您将 1.7.9 版的 Angular 作为字典来压缩 1.8.3 版的 Angular,输出将略高于 4 KiB。这表示压缩率 接近 98% 。显然,压缩字典会对加载性能产生很大影响,并且其有效性已在实际应用中得到体现!
不过,在 Web 上实现此流程存在一个挑战。问题在于,如果您使用字典来压缩资源,则需要使用相同的字典来 解压缩 该资源。之前有人尝试在 Web 上实现此流程(即 SDCH),但安全实现起来很困难。这项关于共享字典压缩的最新提案解决了这些问题,同时为静态资源和动态资源都带来了巨大的好处。
Chrome 如何宣传对共享字典的支持
所有浏览器都通过 Accept-Encoding 请求标头 宣传它们支持的压缩算法。标头的内容是以逗号分隔列表形式表示的支持的编码:
Accept-Encoding: gzip, br, zstd
此特定 Accept-Encoding 标头表明,请求资源的浏览器支持 gzip、Brotli 和 ZStandard 压缩算法。然后,响应请求的 Web 服务器可以决定在响应请求时使用哪种算法。
启用共享字典支持并且资源有相关字典可用时,系统会将其他令牌添加到 Accept-Encoding 标头。这些令牌分别是 Brotli 的 br-d 和 ZStandard 的 zstd-d。Chrome 还会包含可用字典的哈希值,这将在下一部分中介绍。
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
如果 Web 服务器配置为识别此令牌,并且它识别该字典,则可以使用该字典针对适用的编码压缩的资源来响应该请求。这在实践中是如何实现的,取决于请求是针对静态资源还是动态资源。
静态资源的共享字典压缩
静态网页资源是指对于请求的网址始终产生相同响应的资源。可压缩的静态网页资源的常见示例包括 JavaScript 和 CSS 文件。这些资源通常以某种方式进行版本控制,以用于缓存目的,有时会在文件名中使用文件内容的哈希值(例如 styles.abcd1234.css),或者使用其他某种方法对资源进行指纹识别。这些资源类型非常适合共享字典提供的增量压缩,因为静态资源通常会缓存很长时间,并且往往会定期更新。
可以通过为其设置 Use-As-Dictionary 响应标头来为静态资源指定字典。标头采用几个键值对之一,但唯一必需的键值对是 match,它接受 URLPattern 语法,用于指定应使用字典的资源路径:
Use-As-Dictionary: match="/dist/styles.*.css"
您可以将 Use-As-Dictionary 标头视为一种机制,它适用于与其中指定的模式匹配的资源的未来版本。因此,假设您的网站在一个 CSS 文件中发布其所有样式。为简单起见,假设该资源的第一个版本位于 /dist/styles.v1.css,并且随附一个 Use-As-Dictionary 响应标头,其中包含 /dist/styles.*.css 的 match 值。
过一段时间后,您更新了网站的 CSS 并发布了新版本,该版本位于 /dist/styles.v2.css。由于先前版本中的 Use-As-Dictionary 响应标头中使用的 match 值适用于此请求,因此浏览器将发送一个 Available-Dictionary 标头,其中包含编码为 结构化字段字节序列的字典的哈希值:
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
此时,服务器需要在其端配置压缩,以确保使用匹配的字典。然后,系统会发送使用该字典压缩的资源,并使用用户浏览器缓存中的可用字典对其进行解压缩。
如果您经常为网站发布新代码,增量压缩会很有帮助。不过,该过程非常灵活。如果浏览器未确定用户的浏览器缓存中提供了字典,则不会在 Accept-Encoding 标头中指定额外的 br-d 或 zstd-d 令牌。 在这种情况下,系统会应用标准压缩流程。
动态资源的共享字典压缩
动态资源也可以受益于共享字典压缩。动态资源是指根据上下文而变化的资源,例如新闻网站,其中主页会随着新闻的发布而频繁更新。HTML 文档通常是动态资源。在这种情况下,字典可以包含网站的大部分常见 HTML 结构和模板代码,从而生成压缩后的网页,其中仅发送每个网页的独特部分。
由于动态生成的资源的性质,必须在客户端上加载字典以供日后使用。提前加载字典意味着将共享字典压缩应用于动态资源是推测性的。在这种情况下,希望您的网站获得足够的流量,以便将字典费用分摊到大量导航中。如果您决定尝试一下,第一步是在网页 HTML 中使用 <link> 元素指定字典的位置:
<link rel="dictionary" href="/dictionary.dat">
当 Chrome 遇到此 <link> 元素时,它 可能会 在网页空闲时以低优先级提取字典,以避免带宽争用。字典本身的响应必须指定 Use-As-Dictionary 标头,并指定它适用于哪个动态资源路径:
Use-As-Dictionary: match="/product/*"
从这里开始,流程与静态资源大致相同。浏览器会看到字典本身适用于匹配的资源,并且浏览器会将 Available-Dictionary 标头附加到请求中,其中包含字典内容的哈希值,同样类似于前面介绍的静态资源流程。
在构建时压缩静态资源
如果您熟悉捆绑器,您可能熟悉各种捆绑器插件,这些插件可以在构建时压缩资源,然后提供这些压缩后的资源。例如,Apache 允许您使用指令在请求时提供这些预压缩的资源。
大多数支持压缩的基于 Node.js 的捆绑器都使用 Node 的内置 Zlib 库。Zlib 提供对 Brotli 的支持,并且使用它的捆绑器通常提供一个接口,用于将选项直接传递到 Zlib,后者 支持字典辅助压缩。以下是一些支持使用字典的捆绑器:
- webpack 的
CompressionWebpackPlugin,通过其compressionOptions接口。 rollup-plugin-brotli提供了一个options配置,该配置直接传递到 Node.js 中的 Zlib,您可以在其中指定字典。- 适用于 esbuild 的
esbuild-plugin-compress第三方插件 还提供对 Node.js 中 Zlib 选项的访问权限。
请注意,任何给定版本的资源的可用字典都可以使用资源的任何先前版本之一。这意味着您需要分析用户流量并相应地制定计划。力求平衡,并尽可能生成对最多回访用户有益的资源。CDN 提供商目前正在尝试共享字典压缩。目前还没有可供公开使用的实现,但我们预计这种情况会发生变化!
试试看!
将共享字典压缩与浏览器的现有压缩功能集成后,可能会大幅提升经常发布更新的生产代码并从回访用户那里获得大量流量的网站的加载性能。如果您有兴趣尝试共享字典压缩,可以选择以下两种方式:
- 如果您只是想自己尝试使用共享字典压缩,以便了解其工作原理,可以在
chrome://flags页面上启用压缩字典传输 实验性功能。 - 如果您有兴趣在生产网站上试用此功能,并了解共享字典压缩如何让实际用户受益,请注册源试用以获取令牌,并了解源试用的运作方式。
总结
我们对 Web 压缩技术的这一重大进步感到非常兴奋,以及它能让人们每天使用的现有应用的速度提升多少。我们鼓励您尝试一下,最重要的是,如果您尝试了,我们希望听到您的想法!如果您发现 bug,请在 crbug.com 上提交。如需其他资源和工具,请访问 use-as-dictionary.com。最后,如果您有兴趣深入了解其工作原理,说明文档将是很好的下一步!