Speculation Rules:prefetch 与 prerender 的边界
比较 Speculation Rules 的资格、激活、放弃、凭据、副作用与安全 fixture。
BotBrowser Team
BotBrowser 可以重复一个已授权的浏览器上下文并记录页面可见的导航结果,但不宣称能在某个具体版本中启用、强制或测量 Speculation Rules。实际决策应更窄:当未来导航可以安全地提前取得响应时使用 prefetch;只有在隐藏文档可以创建、激活或放弃而不产生不需要的工作时才使用 prerender。资格和生命周期由浏览器决定,应用只提供提示和普通回退路径。
TL;DR
prefetch准备可能的响应,prerender创建可能被激活的隐藏文档;两者都不保证浏览器一定请求或渲染目标。- 资格取决于规则、URL、来源、策略、设备条件和实现。规则匹配不等于网络请求已经发生。
- 激活会把推测文档变成可见文档。激活前可能放弃,因此初始化必须能容忍永远不显示的文档。
- 凭据、Cookie、存储、分析、媒体、WebSocket 和写入都是副作用边界。推测目标应保持只读,并在真实激活后再提交状态。
- 合成 fixture 可以分开记录规则输入、请求意图、激活和放弃,不声称真实浏览器已经运行它。
Contents
- Prefetch 与 prerender 不是同一承诺
- 资格由浏览器决定
- 激活与放弃构成生命周期
- 凭据、副作用与隐私边界
- 可复制 fixture 与受限记录
- 根据观察到的边界选择回退
- BotBrowser 能力边界
- 实践结论
Prefetch 与 prerender 不是同一承诺
MDN 的 Speculation Rules API 给出描述可能导航的 JSON 格式。浏览器可以取得目标资源,也可以创建隐藏文档;页面不会得到同步的“已接受”结果。普通链接不会因为有规则就获得保证的快速导航。
prefetch 主要是为未来导航取得响应,并由浏览器放入内部缓存。收到字节并不会使目标文档变成活动文档。URL、头部、策略、凭据或浏览器状态变化都可能使后续导航不能复用结果。
prerender 可以创建隐藏上下文、加载目标并运行受限制的初始化,然后等待可能的激活。Chrome prerender 文档描述了激活或丢弃隐藏页面的生命周期。它不是可见标签页,也不是可以随意执行产品写入的后台 worker。
| 提示 | 浏览器可能做什么 | 应用可以假设什么 | 更安全的目标 |
|---|---|---|---|
prefetch | 下载候选资源 | 真实导航前什么都不能确定 | 可缓存、只读的文档 |
prerender | 创建隐藏文档 | 目标可能永远不可见 | 延迟写入的只读外壳 |
| 无提示 | 用户请求时正常导航 | 普通导航生命周期 | 具有明确意图的流程 |
Prefetch 主要消耗网络和缓存;prerender 还消耗 CPU、内存、存储读取和初始化预算。不要对购买、发信、套接字、一次性令牌或会改变状态的 GET 使用它。阅读浏览器性能测量可以区分时间标记与导航:隐藏页面中的标记不代表真实访问。
资格由浏览器决定
WICG Speculation Rules 规范说明规则形状以及用户代理会考虑的条件。href_matches、selector_matches 和 eagerness 是算法输入,并不是浏览器跳过候选的完整原因。
<script type="speculationrules">
{
"prefetch": [
{
"where": { "href_matches": "/docs/*" },
"eagerness": "moderate"
}
],
"prerender": [
{
"where": { "selector_matches": "a[data-prerender]" },
"eagerness": "conservative"
}
]
}
</script>
规则匹配仍可能因策略、资源压力、来源或部分语法支持而被拒绝。DNS、TLS、重定向或状态变化也会使结果失效。记录规则来源、URL 类别、响应头、版本、网络条件和回退,而不要写成对用户的绝对结论。
Navigation API 与历史记录指南说明看见 URL 不等于有人访问目标。安全上下文指南补充了请求强大能力前的前置检查。分析应依赖激活信号,而不是单独的请求。
激活与放弃构成生命周期
使用四个状态:已声明、具备资格、已激活、已放弃。已声明表示页面提供了 JSON;具备资格表示浏览器考虑该候选,并不表示已经下载;已激活表示可见导航;已放弃表示被丢弃、过期或被替换而未激活。
激活是分析、持久化个性化、预订、变更和第三方嵌入可以开始的时点。放弃很正常:用户选择其他链接、网络中断或浏览器释放内存都可能发生。定时器和内存句柄要幂等清理,不要把未显示的候选当作用户错误。
| 状态 | fixture 可以保存的证据 | 不安全的解释 |
|---|---|---|
| 已声明 | JSON 指纹和 URL 类别 | 浏览器已经接受规则 |
| 具备资格 | 浏览器诊断(若可用) | 请求一定发生 |
| 已激活 | 可见导航或应用事件 | 初始化只运行了一次 |
| 已放弃 | 丢弃或过期记录 | 用户拒绝了目标 |
事件可能交错。使用合成 fixture 标识;worker 和 service worker 要分开检查隐藏阶段与可见阶段。即使没有可移植的激活事件,也必须保留页面的必需内容。
凭据、副作用与隐私边界
Cookie、缓存、授权头、client hints、referrer policy 和 service worker 都可能改变目标收到的内容。确切行为由来源、凭据模式、策略和浏览器共同决定。fixture 不应依赖真实账号 Cookie 或生产令牌。
分开只读路由和写入路由。公开、可缓存的外壳比创建订单、消耗令牌的 URL 更适合推测;即使 GET 也可能产生服务器副作用。授权和幂等性仍然是服务器责任。
隐藏文档可能在可见前发送 beacon,从而夸大访问量。把不可逆分析延后到可见导航确认之后。DNS 泄漏防护说明辅助查找需要单独审查;prefetch 和 prerender 也必须纳入声明的网络策略。
使用 test-user-17、order-synthetic-42 和自有接收端。采集时就删除完整 Cookie、referrer 和敏感查询参数,限制保存时间,并指定删除责任人。
可复制 fixture 与受限记录
下面的 fixture 只有声明作用,不证明浏览器接受规则、取得资源或激活 prerender。
<script type="speculationrules">
{
"prefetch": [
{
"urls": ["/fixture/read-only-shell.html"],
"eagerness": "immediate"
}
],
"prerender": [
{
"urls": ["/fixture/activation-shell.html"],
"eagerness": "conservative"
}
]
}
</script>
<a href="/fixture/read-only-shell.html" data-case="prefetch">Read-only shell</a>
<a href="/fixture/activation-shell.html" data-case="prerender">Activation shell</a>
<output id="speculation-status">not observed</output>
{
"fixture": "speculation-boundary-v1",
"candidate": "/fixture/activation-shell.html",
"hint": "prerender",
"browser": "declared product, version, channel, and OS",
"policy": "response and permissions policy revision",
"credentials": "synthetic, no account cookie",
"declared": true,
"eligible": "unknown until a run records it",
"activated": "unknown until a visible navigation records it",
"abandoned": "unknown until the lifecycle ends",
"observed": null,
"fallback": "ordinary navigation remains available",
"dataClass": "synthetic"
}
准备一个只读目标和一个只显示激活标记的目标,两者都不写入状态。可以用被规则省略的 URL 验证普通链接仍可用,但没有请求不等于浏览器阻止了它。真正运行时,再在受控证据中增加精确版本、策略、结果和放弃原因。
根据观察到的边界选择回退
| 情况 | 决策 | 原因 |
|---|---|---|
| 只读且可缓存的目标 | 选择 prefetch 或普通导航 | 成本和副作用更小 |
| 延迟写入的可见外壳 | 考虑保守的 prerender | 隐藏初始化仍可回收 |
| 加载时就改变状态 | 不使用 prerender | 丢弃可能已经产生动作 |
| 激活前需要敏感凭据 | 使用明确导航和授权 | 减少意外披露 |
| 支持或策略未知 | 保留普通链接 | 提示不是兼容性保证 |
先比较规则、最终响应、URL、来源、凭据模式、版本和策略,再决定使用哪种提示。WICG、MDN 和 Chrome 文档说明了语法与限制,但不构成对任意版本的实测支持。
BotBrowser 能力边界
BotBrowser 可以将已授权 profile 用于重复声明的上下文,并在团队决定运行自有 fixture 时暴露结果。它不能强制浏览器接受候选、激活 prerender、读取实现私有的资格判断,也不能保证第三方没有收到请求。BotBrowser 高级功能文档没有宣称实现 Speculation Rules。
未来的结果必须限定在指定 profile、版本、系统、策略和 fixture 修订中。页面加载成功不等于所有候选有资格,也不等于没有推测请求。不要利用推测来规避授权、同意、隐私控制或服务方限额。
FAQ
Prefetch 是否代表用户访问了目标?
不是。响应可能在没有可见导航时就被取得,之后也可能放弃。只有激活后才应计为访问。
Prerender 是否总是更快?
不是。它可能减少激活工作,但会消耗更多内存、CPU 和初始化预算,也可能被资源压力丢弃。
推测请求会携带凭据吗?
它受凭据、来源、策略、缓存和 service worker 影响。应使用合成值或不使用值,不能默认匿名。
什么时候发送分析事件?
等可见导航确认后发送,避免把放弃的隐藏文档算成访问。
资格未知时怎么办?
保留普通链接并标记结果未验证,必需内容不能依赖推测结果。
Sources
- WICG Speculation Rules 规范
- MDN:Speculation Rules API
- Chrome:Prerender pages
- BotBrowser:Advanced features
实践结论
对能承受提前取得且只读的响应选择 prefetch;只有能在隐藏状态下初始化、激活或放弃而不产生不可逆写入的文档才考虑 prerender。资格属于浏览器,激活代表可见意图,推测请求只是候选活动。凭据、写入和分析必须等待明确授权。
安全的下一步是在自有来源放置 fixture,保持普通链接可用,并把已声明、具备资格、已激活和已放弃分别记录。未来运行只说明一个具体版本的行为,不证明通用支持,也不会让 BotBrowser 变成 Speculation Rules 实现。
本文属于指南: Web 平台能力面:一致性复核地图