使用 Signed Exchange 优化 LCP

如何衡量和优化已签名广告交易,以充分发挥其优势

Devin Mullins
Devin Mullins

签名广告交易 (SXG) 是一种用于提升网页速度(主要是 Largest Contentful Paint [LCP])的方法。当引荐网站(目前为 Google 搜索)链接到某个网页时,可以在用户点击链接之前将该网页预提取到浏览器缓存中。

您可以构建这样的网页:在预提取时,渲染网页的关键路径上无需网络连接!在 4G 连接上,此网页加载时间从 2.8 秒缩短到 0.9 秒(剩余的 0.9 秒主要由 CPU 使用时间所占):

目前,发布 SXG 的大多数用户都使用 Cloudflare 的易用自动签名广告交易 (ASX) 功能(不过,也存在开源选项):

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

在很多情况下,只需选中相应复选框以启用此功能,即可获得上述显著改进。有时,您还需要执行一些其他步骤,以确保这些 SXG 在流水线的每个阶段都能按预期运行,并优化网页以充分利用预加载功能。

在 Cloudflare 发布后的过去几个月里,我一直在各种 论坛上阅读和回复问题,并学习如何为网站提供建议,确保它们能够充分利用 SXG 部署。本文汇集了我的一些建议。我将引导您完成以下步骤:

简介

SXG 是一种文件,其中包含网址、一组 HTTP 响应标头和响应正文,所有这些内容均由 Web PKI 证书加密签名。浏览器加载 SXG 时,会验证以下所有内容:

  • SXG 未过期。
  • 签名与网址、标头、正文和证书相符。
  • 证书有效且与网址相符。

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

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

分析

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

按如下方式生成不使用 SXG 的测试:

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

按照上述相同的步骤使用 SXG 生成测试,但在点击开始测试之前,请前往脚本标签页,粘贴以下 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 Validator Chrome 扩展程序访问您的网页,然后点击扩展程序图标查看缓存网址:

SXG 验证器,其中显示了包括网址在内的缓存信息

完成这些测试后,前往测试历史记录,选择这两项测试,然后点击比较

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

&medianMetric=LCP 附加到比较网址,以便 WebPageTest 为比较的每组选择平均 LCP 值的运行作业。(默认是按速度指数计算的中位数。)

如需比较广告瀑布流,请展开广告瀑布流不透明度部分,然后拖动滑块。如需查看视频,请点击调整幻灯影片设置,向下滚动该对话框,然后点击查看视频

如果 SXG 预提取成功,您会发现“使用 SXG”广告瀑布流不包含 HTML 行,并且子资源的提取会更早开始。例如,请在此处比较“前”和“后”图片:

不使用 SXG 预提取的网络广告瀑布流;第一行是 HTML 提取,耗时 1050 毫秒 包含 SXG 预提取的网络广告瀑布流;HTML 已预提取,所有子资源可提前 1050 毫秒开始提取

调试

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

发布

确保您的网页以 SXG 的形式生成。为此,您需要假装成抓取工具。最简单的方法是使用 SXG Validator Chrome 扩展程序

SXG 验证器,显示对勾标记 (✅) 和内容类型为 application/signed-exchange;v=b3

该扩展程序使用 Accept 请求标头提取当前网址,其中表明它更喜欢 SXG 版本。如果您在“Origin”(来源)旁边看到对勾标记 (✅),则表示系统返回了 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,并可能会将其提供给多位访问者。如果您根据用户的 Cookie 向不同的用户提供不同的 HTML,那么他们可能会看到不正确的体验,例如看到已登出状态的视图。

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

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

dump-signedexchange

dump-signedexchange -verify -uri $URL

如果 SXG 存在且有效,您会看到 SXG 的直观易读的打印输出。否则,系统会显示错误消息。

编入索引

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

使用开发者工具查看 Google 搜索结果,其中显示了指向 webpkgcache.com 的锚点标记

如果 Google 搜索认为用户可能会点击某个结果,还会预加载该结果:

使用 DevTools 查看 Google 搜索结果,其中显示了 webpkgcache.com 的 rel=prefetch 链接

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

您还可以前往 DevTools 中的“Network”标签页,然后搜索包含 webpkgcache 的网址,以查看预提取的证据。

如果 <a> 指向 webpkgcache.com,则表示已签名的广告交易平台的 Google 搜索索引编制功能正常运行。您可以直接跳至提取部分。

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

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

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

如果没有 digest 标头,则可能表示未向 Googlebot 提交 SXG,或者自您启用 SXG 以来索引未更新。

如果系统成功抓取了 SXG,但仍未关联到该 SXG,则可能是因为该 SXG 不符合 SXG 缓存要求。下一部分将介绍这些内容。

提取

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

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

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

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

SXG 验证器显示一个叉号 (❌) 和一条警告消息,其中指出

在这种情况下,网页的运作方式与启用 SXG 之前完全相同。Google 将链接到原始主机上的网页,而不会预提取 SXG。

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

SXG 验证器显示沙漏图标 (⌛),但没有显示警告消息

有关 SXG 的 Google 开发者文档中还提供了有关手动查询缓存的说明。

优化

如果 SXG Validator Chrome 扩展程序显示所有对勾标记 (✅),则表示您的 SXG 可以向用户提供!请继续阅读,了解如何优化网页,以便从 SXG 中最大限度地缩短 LCP。

max-age

SXG 过期后,Google SXG 缓存将在后台提取新副本。在等待提取期间,系统会将用户定向到其原始主机上的页面,该页面未预提取。您设置的 Cache-Control: max-age 越长,此后台提取的发生频率就越低,因此通过预提取可以缩短 LCP 的频率。

这是在性能和新鲜度之间进行权衡的结果,借助缓存,网站所有者可以为 SXG 提供介于 2 分钟到 7 天之间的最长有效期,以满足每个网页的具体需求。我们发现,在以下情况下,这种情况更为常见:

  • max-age=86400(1 天)或更长时间效果较好
  • max-age=120(2 分钟)不支持

随着我们对数据的深入研究,希望能进一步了解这两者之间的价值。

user-agent

有一次,我发现使用预提取的 SXG 时 LCP 增加了。我运行了 WebPageTest,比较了启用和不启用 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 搜索中的其他预提取内容:

显示 /sub/…/image.jpg 预提取的 Google 搜索结果,其中包含 DevTools 的“Network”标签页

如需针对 LCP 进行优化,请仔细查看您的广告瀑布流,并找出渲染最大的元素的关键路径中的资源。如果无法预提取,不妨考虑是否可以将其从关键路径中移除。请留意在加载完毕之前会隐藏网页的脚本。

Google SXG Cache 允许最多 20 次子资源预加载,ASX 确保不会超出此限制。不过,添加过多子资源预加载项可能会有风险。为了阻止跨站跟踪,浏览器仅会在所有子资源均已提取时使用预加载的子资源。子资源越多,在用户点击进入您的网页之前,所有子资源都完成预提取的可能性就越小。

SXG 验证器目前不会检查子资源;在此期间,如需进行调试,请使用 curldump-signedexchange

测量

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

服务器端指标

在衡量首字节显示前的耗时 (TTFB) 等服务器端指标时,请务必注意,您的网站只会向接受该格式的抓取工具提供 SXG。请仅衡量来自真实用户(而非机器人)的请求的 TTFB。您可能会发现,生成 SXG 会增加抓取工具请求的 TTFB,但这对访问者的体验没有影响。

客户端指标

SXG 对客户端指标(尤其是 LCP)的速度提升最为显著。在衡量这些更改的影响时,您只需启用 Cloudflare ASX,等待 Googlebot 重新抓取,再等待 28 天以汇总 Core Web Vitals (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 网页加载中,这些网页加载的 LCP 可能天生不同:

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

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

显示推荐设置的 Google Analytics 维度编辑器

创建一个名为“SXG 反事实”的自定义细分,并将以下过滤条件按 AND 运算组合在一起:

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

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

在网站模板中,在 Google Analytics 代码段上方添加以下代码段。这是特殊语法,ASX 在生成 SXG 时会将 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%

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

网页指标报告,其中包含 SXG 对照组和 SXG 的选项

点击“提交”,您应该会看到这两个细分受众群体的 LCP 分布情况。这应该填入“第 75 百分位:LCP 缩短了 Y 毫秒”的 Y:

显示 SXG 对照组和 SXG 的 LCP 分布的 Web Vitals 报告

注意事项

应用上述所有过滤条件后,SXG 反事实页面加载应该包含以下内容:

  • 缓存未命中:如果 Google SXG 缓存中没有给定网址的最新 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 对您的网站和用户有益。

如果您对如何提升 SXG 效果有其他建议,欢迎与我们联系!在 developer.chrome.com 上报告 bug,并附上您建议的改进。

如需详细了解已签名广告交易,请参阅 web.dev 文档Google 搜索文档