使用 Signed Exchange 优化 LCP

如何衡量和优化 Signed Exchange,充分提升其效果

Devin Mullins
Devin Mullins

Signed Exchange (SXG) 是一种提升网页速度的方法,主要是 Largest Contentful Paint (LCP)。在引荐网站(目前为 Google 搜索)链接指向网页时,这些链接可在用户点击链接之前预提取到浏览器缓存中。

您可以构建这样的网页:在预提取时,呈现网页的关键路径上不需要网络!使用 4G 连接时,网页加载时间从 2.8 秒缩短到 0.9 秒(其余 0.9 秒主要取决于 CPU 使用情况):

如今,发布 SXG 的大多数人都在使用 Cloudflare 简单易用的 Automatic Signed Exchanges (ASX) 功能(但也有开源方案):

Cloudflare 设置面板,其中包含用于启用 Automatic Signed Exchange 的复选框

在许多情况下,选中相应复选框来启用此功能就足以实现上述实质性改进。有时,您还需要执行几个步骤,以确保这些 SXG 在流水线的每个阶段按预期运行,并优化页面以充分利用预提取。

自 Cloudflare 推出以来的几个月里,我一直在各种 论坛上阅读和回复问题,并学习如何向网站提供关于如何确保充分利用 SXG 部署的建议。这篇博文汇集了我的建议。我将向您详细介绍相关步骤:

简介

SXG 是包含网址、一组 HTTP 响应标头和响应正文的文件,均由 Web PKI 证书进行加密签名。浏览器加载 SXG 时,会验证以下所有项:

  • SXG 尚未到期。
  • 签名与网址、标头、正文和证书相匹配。
  • 证书有效且与网址匹配。

如果验证失败,浏览器将放弃 SXG,改为提取已签名网址。如果验证成功,浏览器就会加载带签名的响应,将其视为直接来自该签名网址。这样就可以将 SXG 重新托管在任何服务器上,只要服务器在签名后未过期或未发生修改即可。

对于 Google 搜索,SXG 支持在其搜索结果中预提取网页。对于支持 SXG 的网页,Google 搜索可以预提取其缓存的网页副本,该副本托管在 webpkgcache.com 上。这些 webpkgcache.com 网址不会影响页面的显示或行为,因为浏览器会遵循原始的签名网址。预提取功能可以大大加快网页的加载速度。

分析

如需了解 SXG 的优势,请先使用实验室工具分析 SXG 在可重复条件下的性能。您可以使用 WebPageTest 比较在使用 SXG 预提取时和不使用 SXG 预提取时的瀑布流和 LCP。

生成不使用 SXG 的测试,如下所示:

  • 转到 WebPageTest 并登录。登录后,系统会保存您的测试历史记录,以便您日后更轻松地进行比较。
  • 输入要测试的网址。
  • 转到高级配置。(您将需要使用高级配置进行 SXG 测试,因此在此处使用高级配置有助于确保测试选项相同。)
  • Test Settings(测试设置)标签页中,将“Connection”(连接)设置为 4G 并将“Number of Tests to Run”(要运行的测试数)增加到 7 可能会有所帮助。
  • 点击开始测试

按照与上述步骤相同的步骤,使用 SXG 生成测试,但在点击 Start Test 之前,请前往 Script 标签页,粘贴以下 WebPageTest 脚本,然后按照指示修改两个 navigate 网址:

// Disable log collection for the first step. We only want the waterfall for the target navigation.
logData 0

// Visit a search result page that includes your page.
navigate https://google.com/search?q=site%3Asigned-exchange-testing.dev+image

// Wait for the prefetch to succeed.
sleep 10

// Re-enable log collection.
logData 1

// Navigate to the prefetched SXG on the Google SXG Cache.
navigate https://signed--exchange--testing-dev.webpkgcache.com/doc/-/s/signed-exchange-testing.dev/sxgs/valid-image-subresource.html

对于第一个 navigate 网址,如果您的网页尚未显示在任何 Google 搜索结果中,您可以使用此预提取网页生成用于此目的的假想搜索结果页。

要确定第二个 navigate 网址,请使用 SXG 验证工具 Chrome 扩展程序访问您的网页,然后点击扩展程序图标以查看缓存网址:

显示缓存信息(包括网址)的 SXG 验证器

完成这些测试后,前往 Test History(测试历史记录),选择这两个测试,然后点击 Compare

“测试历史记录”页面,其中已选中两项测试并突出显示了“比较”按钮

&medianMetric=LCP 附加到比较网址,以便 WebPageTest 为比较的两侧选择 LCP 中间值运行的运行。(默认值为速度指数的中位数)。

如需比较瀑布流,请展开 Waterfall Opacity(瀑布透明度)部分,然后拖动滑块。要观看视频,请点击调整幻灯影片设置,在该对话框中向下滚动,然后点击观看视频

如果 SXG 预提取成功,您会看到“with SXG”广告瀑布流不包含 HTML 行,并且对子资源的提取会更早开始。例如,下面是比较“之前”和“之后”的对比:

没有 SXG 预提取的网络瀑布流;第一行是 HTML 提取,耗时 1050 毫秒 使用 SXG 预提取的网络瀑布流;HTML 已预提取,允许所有子资源提前 1050 毫秒开始提取

调试

如果 WebPageTest 显示正在预提取 SXG,则表明它已成功完成流水线的所有步骤;您可以跳至优化部分,了解如何进一步改进 LCP。否则,您需要找出流水线中哪个位置出现了故障以及失败原因;请继续阅读下文,了解操作方法。

正在发布

确保您的网页是作为 SXG 生成的。为此,您需要冒充抓取工具。最简单的方法是使用 SXG 验证工具 Chrome 扩展程序

显示对勾标记 (✅) 的 SXG 验证工具,内容类型为 application/signed-Exchange;v=b3

该扩展程序会提取当前网址,其中的 Accept 请求标头表明其首选 SXG 版本。如果“源”旁边出现对勾标记 (✅),则表示系统返回了 SXG;您可以跳至编入索引部分。

如果您看到叉号 (❌),则表示 SXG 未退货:

SXG 验证工具显示叉号 (❌) 和内容类型为 text/html

如果 Cloudflare ASX 已启用,则出现十字标记 (❌) 的最可能原因是缓存控制响应标头阻止了它。ASX 会检查具有以下名称的标头:

  • Cache-Control
  • CDN-Cache-Control
  • Surrogate-Control
  • Cloudflare-CDN-Cache-Control

如果其中任何标头包含以下任一标头值,都会阻止生成 SXG:

  • private
  • no-store
  • no-cache
  • max-age 小于 120(除非被大于或等于 120 的 s-maxage 替换)

在这种情况下,ASX 不会创建 SXG,因为 SXG 可能会被缓存并重复利用给多次访问和多个访问者使用。

出现十字标记 (❌) 的另一个可能原因是存在这些有状态响应标头Set-Cookie 除外)。ASX 移除了 Set-Cookie 标头,以符合 SXG 规范。

另一个可能的原因是存在 Vary: Cookie 响应标头。Googlebot 在没有用户凭据的情况下抓取 SXG,并可能会将 SXG 提供给多个访问者。如果您根据不同用户的 Cookie 为其提供不同的 HTML,则他们可能会看到错误的体验,例如退出登录。

除了 Chrome 扩展程序,您还可以使用 curl 等工具:

curl -siH "Accept: application/signed-exchange;v=b3" $URL | less

dump-signedexchange

dump-signedexchange -verify -uri $URL

如果该 SXG 存在且有效,您将看到 SXG 的直观易读输出。否则,您将会看到一条错误消息。

索引编制

确保您的 SXG 已被 Google 搜索成功编入索引。打开 Chrome 开发者工具,然后对您的网页执行 Google 搜索。如果该网页已被作为 SXG 编入索引,那么 Google 指向您网页的链接将包含一个指向 webpkgcache.com 副本的 data-sxg-url

带有开发者工具的 Google 搜索结果,其中显示了指向 webpkgcache.com 的锚标记

如果 Google 搜索认为用户可能会点击结果,还会预提取该结果:

带有开发者工具的 Google 搜索结果,显示了 webpkgcache.com 的 rel=prefetch 链接

<link> 元素指示浏览器将 SXG 下载到其预提取缓存中。当用户点击 <a> 元素时,浏览器将使用缓存的 SXG 来呈现页面。

您也可以前往开发者工具中的“Network”标签页,搜索包含 webpkgcache 的网址,查看预提取的证据。

如果 <a> 指向 webpkgcache.com,这意味着 Signed Exchange 的 Google 搜索索引编制功能正常。您可以跳到 Ingestion(提取)部分。

否则,可能是因为在您启用 SXG 后,Google 尚未重新抓取您的网页。不妨试用 Google Search Console 网址检查工具

Search Console 网址检查工具,依次点击“查看抓取的网页”和“更多信息”

digest: mi-sha256-03=... 标头的存在表示 Google 已成功抓取 SXG 版本。

如果 digest 标头不存在,则可能表示 SXG 未提供给 Googlebot,或者自您启用 SXG 后索引尚未更新。

如果 SXG 已成功抓取,但仍未关联,则可能不符合 SXG 缓存要求。这些内容将在下一部分进行介绍。

注入

当 Google 搜索将 SXG 编入索引时,它会将其副本发送到 Google SXG Cache,后者会根据缓存要求对其进行验证。Chrome 扩展程序会显示结果:

SXG 验证工具显示对勾标记 (✅),且没有警告消息

如果您看到对勾标记 (✅),则可以直接跳转到优化

如果不符合要求,您会看到叉号 (❌) 和警告消息,说明原因:

SXG 验证工具显示叉号 (❌) 和警告消息:

在这种情况下,该页面将像启用 SXG 之前一样正常运行。Google 会链接到其原始主机上的相应网页,而不会预提取 SXG 内容。

如果缓存副本已过期并在后台重新提取,您会看到一个沙漏 (⌛):

显示沙漏 (⌛) 且不显示警告消息的 SXG 验证工具

SXG 上的 Google 开发者文档还包含如何手动查询缓存的说明。

优化

如果 SXG 验证工具 Chrome 扩展程序显示所有对勾标记 (✅),则表示您有一个 SXG 可以向用户投放!请继续阅读下文,了解如何优化网页,以便通过 SXG 最大限度地提升 LCP 效果。

max-age

当 SXG 过期后,Google SXG Cache 将在后台提取新副本。在等待提取期间,系统会将用户定向到该网页的原始主机(非预提取)。设置 Cache-Control: max-age 的时间越长,此后台提取的发生频率就越低,因此预提取可以越频繁地减少 LCP。

这是性能和新鲜度之间的权衡,缓存允许网站所有者为 SXG 提供 2 分钟到 7 天的最长存在时间,以满足每个页面的特定需求。有趣的是,我们发现:

  • max-age=86400(1 天)或更长时间更有助于提升效果
  • max-age=120(2 分钟)不

随着对数据的研究,我们希望可以对两者之间的值有所了解。

user-agent

有一次,我看到在使用预提取 SXG 时 LCP 增加。我运行了 WebPageTest,比较不使用 SXG 预提取和使用 SXG 预提取时的中位数结果。点击下方的之后

没有 SXG 预提取的网络瀑布流;LCP 为 2 秒 采用 SXG 预提取的网络瀑布流;HTML 已预提取,允许所有子资源提前 800 毫秒开始提取,但 LCP 为 2.1 秒

我发现预提取功能有效。HTML 从关键路径中移除,因此所有子资源都能提前加载。但 LCP(绿色虚线)从 2 秒增加到了 2.1 秒

为了进行诊断,我查看了胶卷。我发现网页在 SXG 中的呈现方式不同。在纯 HTML 中,Chrome 确定 LCP 的“最大元素”是标题。然而,在 SXG 版本中,页面添加了延迟加载的横幅广告,这会将标题推到非首屏位置,并将新的最大元素设为延迟加载 Cookie 意见征求对话框。所有内容的呈现速度都比以前更快,但布局的变化导致该指标报告的显示速度变慢。

经过深入分析,我发现布局差异的原因在于页面因 User-Agent 而异,并且逻辑中存在错误。尽管 SXG 抓取标头指明了移动版网页,但该网页投放的是桌面版网页。此问题解决后,浏览器再次将网页的标题正确识别为最大的元素。

现在,点击“之后”,我看到预提取的 LCP 下降到 1.3 秒

没有 SXG 预提取的网络瀑布流;LCP 为 2 秒 采用 SXG 预提取的网络瀑布流;LCP 为 1.3 秒

SXG 适用于所有设备规格。为此,请确保满足以下任一条件:

子资源

SXG 可用于预提取子资源(包括图片)以及 HTML。Cloudflare ASX 将扫描 HTML 中是否存在同源(第一方)<link rel=preload> 元素,并将其转换为与 SXG 兼容的链接标头。如需了解详情,请点击此处此处

如果抓取成功,您会看到 Google 搜索中的其他预提取内容:

带有开发者工具的“Network”标签页的 Google 搜索结果,显示了预提取的 /sub/.../image.jpg

若要针对 LCP 进行优化,请仔细查看广告瀑布流,并确定哪些资源位于渲染最大元素的关键路径上。如果无法预提取它们,请考虑是否可以将其从关键路径中移除。请留意有哪些脚本会在网页加载完成之前隐藏网页。

Google SXG Cache 允许预加载最多 20 个子资源,ASX 可确保不会超出此限制。但是,添加过多的子资源预加载存在风险。只有在所有预加载的子资源均已抓取完毕时,浏览器才会使用预加载的子资源,从而防止跨网站跟踪。子资源越多,所有子资源在用户点击到达您的网页前完成预提取的可能性越小。

SXG 验证工具目前不会检查子资源;如需进行调试,请同时使用 curldump-signedexchange

测量

在 WebPageTest 中优化 LCP 改进后,衡量 SXG 预提取对网站整体性能的影响会很有帮助。

服务器端指标

在衡量首字节时间 (TTFB) 等服务器端指标时,请务必注意,您的网站仅向接受 SXG 的抓取工具提供 SXG。将 TTFB 的衡量范围限制为来自真实用户(而非漫游器)的请求。您可能会发现,生成 SXG 会增加抓取工具请求的 TTFB,但这不会影响访问者的体验。

客户端指标

SXG 对客户端指标(尤其是 LCP)的速度优势最大。在衡量它们的影响时,您只需启用 Cloudflare ASX,等待 Googlebot 重新抓取它,再等待 28 天进行核心网页指标 (CWV) 汇总,然后查看新的 CWV 数据。但是,如果这种变化与这段时间内的所有其他变化混合在一起,可能就很难被发现。

相反,我发现“放大”可能受影响的网页加载,并将其构建为:“SXG 影响 X% 的网页浏览量,在第 75 个百分位处将 LCP 提高 Y 毫秒。”

目前,SXG 预提取仅在特定条件下进行:

  • Chromium 浏览器(例如 Chrome 或 Edge,iOS 版除外),M98 或更高版本
  • Referer: google.com 或其他 Google 搜索网域。(请注意,在 Google Analytics(分析)中,引荐标记适用于会话中的所有网页浏览,而 SXG 预提取仅适用于 Google 搜索直接关联的首次网页浏览。)

请阅读“当代研究”部分,了解如何衡量“X% 的网页浏览量”和“将其 LCP 提升 Y 毫秒”。

当代研究

查看真实用户监控 (RUM) 数据时,您应将网页加载划分到 SXG 和非 SXG。这样做时,请务必限制您要查看的一系列网页加载,使非 SXG 端符合 SXG 的资格条件,以免发生选择性偏差。否则,以下所有项将存在于一组非 SXG 页面加载中,这些非 SXG 页面可能具有本质上不同的 LCP:

  • iOS 设备:由于使用 iOS 设备的用户在硬件或网速方面存在差异。
  • 旧版 Chromium 浏览器:原因相同。
  • 桌面设备:出于相同原因,或者由于页面布局导致选择不同的“最大元素”。
  • 同网站导航(访问者访问网站中的链接):因为它们可以重复使用上次网页加载时缓存的子资源。

在 Google Analytics(分析)(UA) 中,创建两个范围为“命中”的自定义维度,一个名为“isSXG”,另一个名为“referrer”。(内置的“来源”维度具有会话级范围,因此不排除同网站浏览。)

采用建议设置的 Google Analytics(分析)维度编辑器

创建一个名为“SXGcounterfactual”的自定义细分,并将以下过滤条件以 AND 关系结合在一起:

  • referrer开头是 https://www.google.
  • Browser”与“Chrome”完全匹配
  • Browser 版本与正则表达式 ^(9[8-9]|[0-9]{3}) 匹配
  • isSXG”与“false”完全匹配
包含推荐过滤条件的 Google Analytics(分析)细分编辑器

创建此细分的副本,将其命名为“SXG”,但参数 isSXGtrue 完全匹配。

在网站模板中,在 Google Analytics(分析)代码段上方添加以下代码段。这是一种特殊语法,在生成 SXG 时,ASX 会将 false 更改为 true

<script data-issxg-var>window.isSXG=false</script>

根据建议自定义 Google Analytics(分析)报告脚本,以记录 LCP。如果您使用的是 gtag.js,请修改 'config' 命令以设置自定义维度(将 'dimension1''dimension2' 替换为 Google Analytics(分析)指定使用的名称):

gtag('config', 'YOUR_TRACKING_ID', {
  'dimension1': String(isSXG),
  'dimension2': document.referrer,
});

如果您使用的是 analytics.js,请按照此处所述修改 'create' 命令。

等待几天收集一些数据后,转到 Google Analytics(分析)“事件”报告,然后添加 SXG 细分的细目。这应该会填上“SXG 影响 X% 的网页浏览量”的 X:

包含 SXG 细分的 Google Analytics(分析)事件报告,显示唯一身份事件数占 12.5%

最后,前往网页指标报告,选择“选择细分”,然后选择“SXGcounterfactual”和“SXG”。

网页指标报告,其中包含 SXG 抗辩通知和 SXG 方面的选择

点击“Submit”(提交),您应该会看到这两个细分的 LCP 分布情况。这应该会填充 Y 以表示“在第 75 个百分位将 LCP 提高 Y 毫秒”:

网页指标报告,显示了 SXGcounterfactual 和 SXG 的 LCP 分布

注意事项

应用上述所有过滤条件后,SXG 的“counterfactual”页面加载应包含以下信息:

  • 缓存未命中:如果 Google SXG Cache 没有针对给定网址获取 SXG 的最新副本,则会重定向到您网站上的原始网址。
  • 其他搜索结果类型:目前,Google 搜索仅支持使用 SXG 搜索标准网页搜索结果和一些其他类型的搜索结果。而另一些网页(如精选摘要和焦点新闻轮播界面)则会链接到您网站上的原始网址。
  • 不符合条件的网址:如果您网站上的某些网页不符合 SXG 使用条件(例如,因为它们不可缓存),它们可能会显示在此集中。

SXG 网页加载和上述非 SXG 网页加载之间可能存在剩余的偏差,但此偏差的幅度应小于“当代研究”部分顶部提到的偏差幅度。例如,不可缓存的网页可能比可缓存的网页更慢或更快。如果您怀疑这可能是个问题,请考虑查看仅限符合 SXG 条件的网址的数据,以了解其结果是否与整体研究相符。

如果您的网站包含部分 AMP 网页,它们可能无法因启用 SXG 而实现性能提升,因为这些网页已从 Google 搜索中预提取。您可以考虑添加过滤条件以排除此类网页,从而进一步“放大”相关更改。

最后,即使解决了所有选择性偏见,也存在幸存者偏见,导致 LCP 改进看起来像是 RUM 统计信息的降级。这篇文章很好地说明了这种风险,并建议通过某种形式的放弃指标来检测是否发生了此类情况。

调查前/后

为了证实这项当代研究的结果,比较一下启用 SXG 前后的 LCP 可能很有用。为了消除上述潜在偏见,请勿将浏览次数限制为 SXG。应查看符合 SXG 条件的结果,即上述细分定义,但没有 isSXG 限制。

请注意,Google 搜索最多可能需要几周时间才能重新抓取您网站上的所有网页,以便确定是否已为这些网页启用 SXG。在这几周内,可能还会出现其他偏差:

  • 新浏览器发布或用户硬件改进可能会加快网页加载速度。
  • 节假日等重大事件可能会导致流量出现偏离正常情况。

此外,您不妨查看一下使用前后的第 75 个百分位 LCP 前后的整体情况,以便确认上述研究。了解人口的子集并不一定能了解总体人群。例如,假设 SXG 将网页加载的 10% 提高了 800 毫秒。

  • 如果这些都已经是网页加载速度最快的 10%,那么第 75 百分位也不会受到影响。
  • 如果它们是网页加载速度最慢的 10%,但相较于第 75 百分位的 LCP 开始慢 800 毫秒,则不会影响第 75 百分位。

这些是极端情况的示例,可能并未反映真实情况,但希望能说明问题所在。在实践中,对于大多数网站,SXG 可能会影响第 75 个百分位。跨网站导航往往最慢,预提取往往会有显著改进。

为某些网址选择不自动更改

最后,比较 SXG 性能的一种方法是为您网站上的部分网址停用 SXG。例如,您可以设置 CDN-Cache-Control: no-store 标头来阻止 Cloudflare ASX 生成 SXG。我不推荐这样做。

与其他研究方法相比,这种方法可能存在选择偏差的风险。例如,无论将您网站的首页还是类似的热门网址选入对照组或实验组,都会产生很大的影响。

对照组研究

衡量影响的理想方法是进行受限研究。很遗憾,您目前无法执行此类测试。我们计划将来增加对此类测试的支持。

对照组研究具有以下属性:

  • 在实验组中,部分随机的 SXG 网页浏览量会被“保留”,并作为非 SXG 提供。这样,您就可以在对等用户、设备、场景和网页之间进行“对等”比较。
  • 分析中会标记这些受限的(也称为反事实)网页浏览。这样就可以查看数据的“放大”视图,在此视图中,我们可以将对照组中的 SXG 网页加载次数与实验中的 SXG 计数器事实进行比较。这反过来又可以减少其他网页加载时产生的干扰,而这些加载不受 SXG 预提取影响。

这会消除上述可能的选择偏见来源,但不会消除 LCP 幸存者偏见的风险。这两个属性都需要启用浏览器或引荐来源网址。

总结

好了!内容太多了。希望本书能更全面地介绍如何在实验室测试中测试 SXG 性能,如何通过实验室测试在紧密反馈环中优化其性能,以及如何在现实世界中衡量其性能。综合以上所有元素,您将能够充分发挥 SXG 的价值,并确保它们能够让您的网站和用户从中受益。

如果您对如何记录 SXG 性能还有其他建议,请告诉我们!提交针对 developer.chrome.com 的错误,并附上您建议的改进。

如需详细了解 Signed Exchange,请参阅 web.dev 文档Google 搜索文档