数据压缩是一项久经考验的性能优化技术,可缩减符合条件的网页资源的大小。一段时间以来,常见的做法是在网络服务器上主要使用 gzip 压缩常见的基于文本的网页资源(例如 HTML、CSS 和 JavaScript 文件),并将其发送到客户端进行解压缩。这样一来,资源的加载时间就会缩短,而不会影响网页的预期行为。
虽然 gzip 本身就非常高效,但近年来,网络压缩技术又有了进一步的改进。2016 年,Brotli 算法在 Chrome 中发布,为符合条件的资源提供了更好的整体压缩比。到 2017 年底,所有现代浏览器都支持 Brotli,并且服务器对 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 作为字典压缩了版本 1.8.3 的 Angular,输出将仅略高于 4 KiB。这表示压缩率为 近 98%。显然,压缩字典对加载性能有很大影响,并且其有效性已在实际应用中得到了体现!
不过,要想让此流程在网页上正常运行,还存在一个难题。问题在于,如果您使用字典压缩资源,则需要使用同一字典来解压缩资源。此流程之前曾在 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
响应标头一起发送,其中 match
值为 /dist/styles.*.css
。
过了一段时间后,您更新了网站的 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,后者支持字典辅助压缩。以下是一些支持使用字典的捆绑器:
- 通过其
compressionOptions
接口调用 webpack 的CompressionWebpackPlugin
。 rollup-plugin-brotli
提供options
配置,该配置会直接传递到 Node.js 中的 Zlib,在其中可以指定字典。- esbuild 的
esbuild-plugin-compress
第三方插件还提供对 Node.js 中的 Zlib 选项的访问权限。
请注意,任何给定资源版本的可用字典都可以使用资源的任何早期版本之一。这意味着,您需要分析用户流量并据此制定计划。力求平衡,尽可能制作出能够让尽可能多的回访用户受益的资源。CDN 提供商目前正在尝试使用共享字典压缩。目前还没有任何实现可供公众使用,但我们预计这种情况很快就会改变!
试试看!
将共享字典压缩功能与浏览器的现有压缩功能集成后,对于经常发布更新版正式版代码并从回访者获得大量流量的网站,其加载性能有望大幅提升。如果您有兴趣尝试使用共享字典压缩功能,可以通过以下两种方式进行:
- 如果您只是想自行调整共享字典压缩功能,以了解其运作方式,可以在
chrome://flags
页面上启用压缩字典传输实验性功能。 - 如果您有兴趣在生产环境网站上试用此功能,并了解共享字典压缩功能对真实用户有何益处,请注册参与源代码试用以获取令牌,并了解源代码试用的运作方式。
总结
我们非常高兴看到 Web 压缩技术取得了如此重大的进步,以及它能让人们每天使用的现有应用运行得多快。我们鼓励您试用该功能,最重要的是,我们希望听到您的想法!如果您发现 bug,请前往 crbug.com 提交 bug。如需更多资源和工具,请访问 use-as-dictionary.com。最后,如果您有兴趣深入了解其运作方式,不妨参阅说明文档!