如何衡量和优化已签名广告交易,以充分发挥其效果
签名广告交易 (SXG) 是一种用于提升网页速度(主要是 Largest Contentful Paint [LCP])的方法。当引荐网站(目前为 Google 搜索)链接到某个网页时,可以在用户点击链接之前将该网页预提取到浏览器缓存中。
您可以使网页在预提取后无需在呈现网页的关键路径上具有网络!在 4G 连接上,此网页加载时间从 2.8 秒缩短到 0.9 秒(剩余的 0.9 秒主要由 CPU 使用时间所占):
目前,大多数发布 SXG 的用户都在使用 Cloudflare 简单易用的 Automatic Signed Exchange (ASX) 功能(不过也提供开源方案):
在很多情况下,只需选中相应复选框以启用此功能,即可获得上述显著改进。有时,您还需要执行一些其他步骤,以确保这些 SXG 在流水线的每个阶段都能按预期运行,并优化网页以充分利用预加载功能。
在 Cloudflare 发布后的过去几个月里,我一直在各种论坛上阅读和回复问题,并学习如何为网站提供建议,确保它们能够充分利用 SXG 部署。本文汇集了我的一些建议。我将引导您完成以下步骤:
- 使用 WebPageTest 来分析 SXG 性能。
- 如果“分析”步骤显示 SXG 流水线不起作用,请调试 SXG 流水线。
- 针对 SXG 预加载优化页面,包括设置最佳
max-age
和预加载会阻塞呈现的子资源。 - 选择合适的实验组和对照组,使用 Google Analytics 衡量 SXG 改进效果。
简介
SXG 是一种文件,其中包含网址、一组 HTTP 响应标头和响应正文,所有这些内容均由 Web PKI 证书加密签名。浏览器加载 SXG 时,会验证以下所有内容:
- SXG 未过期。
- 签名与网址、标头、正文和证书一致。
- 证书有效且与网址相符。
如果验证失败,浏览器会放弃 SXG,改为提取已签名的网址。如果验证成功,浏览器会加载已签名的响应,并将其视为直接来自已签名的网址。这样一来,只要 SXG 自签名后未过期或修改,就可以在任何服务器上重新托管 SXG。
对于 Google 搜索,SXG 支持预提取搜索结果中的网页。对于支持 SXG 的网页,Google 搜索可以预提取网页的缓存副本(托管在 webpkgcache.com 上)。这些 webpkgcache.com 网址不会影响网页的显示或行为,因为浏览器会遵循原始的已签名网址。预提取可让网页的加载速度加快很多。
分析
如需了解 SXG 的优势,请先使用实验室工具分析可重复条件下的 SXG 性能。您可以使用 WebPageTest 比较启用和不启用 SXG 预加载时的广告瀑布流和 LCP。
在不使用 SXG 的情况下生成测试,如下所示:
- 转到 WebPageTest 并登录。登录后,系统会保存您的测试历史记录,以便您日后更轻松地进行比较。
- 输入您要测试的网址。
- 前往高级配置。(您需要使用高级配置来进行 SXG 测试,因此在此处使用高级配置有助于确保测试选项相同。)
- 在 Test Settings(测试设置)标签页中,将“Connection”(连接)设置为 4G 并将“Number of Tests to Run”(要运行的测试数量)增加到 7,可能会很有帮助。
- 点击 Start Test。
按照上述相同的步骤使用 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 扩展程序访问您的网页,然后点击扩展程序图标查看缓存网址:
完成这些测试后,前往测试历史记录,选择这两项测试,然后点击比较:
将 &medianMetric=LCP
附加到比较网址,以便 WebPageTest 为比较的每组选择 LCP 中位数较低的运行作业。(默认是按速度指数计算的中位数。)
若要比较各个瀑布,请展开瀑布流不透明度部分,然后拖动滑块。要观看视频,请点击调整幻灯影片设置,在该对话框中向下滚动,然后点击观看视频。
如果 SXG 预提取成功,您会发现“使用 SXG”广告瀑布流不包含 HTML 行,并且子资源的提取会更早开始。例如,请在此处比较“前”和“后”图片:
调试
如果 WebPageTest 显示 SXG 正在预提取,则表示它已成功通过流水线的所有步骤;您可以跳至优化部分,了解如何进一步改进 LCP。否则,您需要找出相应任务在流水线中的哪个位置失败以及原因;请继续阅读以了解具体方法。
发布
确保您的网页是作为 SXG 生成的。为此,您需要假装成抓取工具。最简单的方法是使用 SXG Validator Chrome 扩展程序:
该扩展程序通过 Accept
请求标头(指明它首选 SXG 版本)来提取当前网址。如果您在“Origin”(来源)旁边看到对勾标记 (✅),则表示系统返回了 SXG;您可以跳至索引编制部分。
如果您看到叉号 (❌),则表示 SXG 未返回:
如果启用了 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 -verify -uri $URL
如果 SXG 存在且有效,您会看到 SXG 的直观易读的打印输出。否则,系统会显示错误消息。
编入索引
确保 Google 搜索已成功编入索引您的 SXG。打开 Chrome 开发者工具,然后在 Google 上搜索您的网页。如果该网页已作为 SXG 编入索引,则指向您网页的链接中会包含一个指向 webpkgcache.com 副本的 data-sxg-url
:
如果 Google 搜索认为用户可能会点击某个结果,还会预加载该结果:
<link>
元素会指示浏览器将 SXG 下载到其预提取缓存中。当用户点击 <a>
元素时,浏览器将使用缓存的 SXG 来呈现页面。
您还可以前往 DevTools 中的“Network”标签页,然后搜索包含 webpkgcache
的网址,以查看预提取的证据。
如果 <a>
指向 webpkgcache.com,则表示 Signed Exchange 的 Google 搜索索引可正常发挥作用。您可以直接跳至提取部分。
否则,这可能是因为自您启用 SXG 后 Google 尚未重新抓取您的网页。请尝试使用 Google Search Console 网址检查工具:
digest: mi-sha256-03=...
标头的存在表示 Google 成功抓取了 SXG 版本。
如果没有 digest
标头,则可能表示未向 Googlebot 提交 SXG,或者自您启用 SXG 以来索引未更新。
如果系统成功抓取了某个 SXG,但仍未链接到它,则可能是因为它不符合 SXG 缓存要求。下一部分将介绍这些内容。
提取
当 Google 搜索对 SXG 进行索引编制时,会将其副本发送到 Google SXG 缓存,后者会根据缓存要求对其进行验证。Chrome 扩展程序会显示以下结果:
如果您看到对勾标记 (✅),则可以直接跳转到优化。
如果不符合要求,您会看到一个叉号 (❌) 和一条说明原因的警告消息:
在这种情况下,网页的运作方式与启用 SXG 之前完全相同。Google 会在不进行 SXG 预提取的情况下链接到原始主机上的网页。
如果缓存的副本已过期,并且正在后台重新提取,您会看到一个沙漏图标 (⌛):
有关 SXG 的 Google 开发者文档中还提供了有关手动查询缓存的说明。
优化
如果 SXG Validator Chrome 扩展程序显示所有对勾标记 (✅),则表明您有可以向用户提供的 SXG!请继续阅读,了解如何优化网页,以便从 SXG 中最大限度地缩短 LCP。
最长年龄
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 预加载的中位数结果。点击下面的之后:
我发现预提取功能已正常运行。HTML 会从关键路径中移除,因此所有子资源都可以更早加载。但 LCP(绿色虚线)从 2 秒增加到了 2.1 秒。
为了诊断这个问题,我查看了胶片条。我发现网页在 SXG 中呈现方式不同。在纯 HTML 中,Chrome 确定 LCP 的“最大元素”是标题。不过,在 SXG 版本中,该网页添加了一个延迟加载的横幅,这会将标题推到折叠线下方,并导致新的最大元素是延迟加载的 Cookie 意见征求对话框。所有内容的呈现速度都比以前快,但由于布局发生了变化,该指标报告的速度变慢了。
我深入研究了一下,发现布局存在差异的原因是页面因 User-Agent
而异,而逻辑中存在错误。尽管 SXG 抓取标头指明了移动版,但它之前提供的却是桌面版网页。解决此问题后,浏览器再次正确识别了网页的标题为其最大的元素。
现在,点击“之后”,我发现预提取的 LCP 下降到 1.3 秒:
SXG 已针对所有外形规格启用。为此,请确保满足以下任一条件:
- 您的网页未按
User-Agent
Vary
(例如,使用自适应设计或单独的移动版/桌面版网址)。 - 如果您的网页使用动态提供内容,则会使用
<meta name=supported-media content=...>
将自身注释为仅限移动设备或仅限桌面设备。
子资源
SXG 可用于预加载 HTML 以及子资源(包括图片)。Cloudflare ASX 会扫描 HTML 以查找同源(第一方)<link rel=preload>
元素,并将其转换为与 SXG 兼容的链接标头。如需了解详情,请参阅此处和此处中的源代码。
如果它能正常工作,您会看到 Google 搜索中的其他预提取内容:
若要针对 LCP 进行优化,请仔细检查广告瀑布流,并确定哪些资源位于渲染最大元素的关键路径上。如果无法预提取,请考虑是否可以将其从关键路径中移除。请留意在加载完成之前隐藏页面的脚本。
Google SXG Cache 允许最多 20 个子资源预加载,ASX 会确保不超过此限制。不过,添加过多子资源预加载项可能会有风险。浏览器仅会在所有子资源均已提取完毕时使用预加载的子资源,以防止跨网站跟踪。子资源越多,所有子资源就越不在用户点击进入您的网页之前完成预提取的可能性就越小。
SXG Validator 目前不会检查子资源;在此期间,如需进行调试,请使用 curl
或 dump-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”,另一个名为“引荐来源网址”。(内置的“来源”维度具有会话级范围,因此不会排除同一网站内的导航。)
使用以下过滤条件以 AND 关系结合起来创建名为“SXGcounterfactual”的自定义细分:
referrer
开头是https://www.google.
- “
Browser
”与“Chrome
”完全匹配 Browser
版本与正则表达式^(9[8-9]|[0-9]{3})
匹配- “
isSXG
”与“false
”完全匹配
创建此细分的副本,将其命名为“SXG”,但使用 isSXG
与 true
完全匹配。
在网站模板中,在 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 对照组”和“SXG”。
点击“提交”,您应该会看到这两个细分受众群体的 LCP 分布情况。这应该填入“第 75 百分位:LCP 缩短了 Y 毫秒”的 Y:
注意事项
应用上述所有过滤条件后,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 效果有其他建议,欢迎与我们联系!在 developer.chrome.com 上报告 bug,并附上您建议的改进。
如需详细了解已签名广告交易,请参阅 web.dev 文档和 Google 搜索文档。