使用 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 搜索文档