Navigation API、历史记录与隐私边界
用受控夹具观察同文档与跨文档导航、history state、事件时序和兼容回退。
BotBrowser Team
BotBrowser 可以在声明的配置中重复已授权的导航夹具,并记录可见的过渡和历史结果;它不能读取其他来源的历史、从 URL 推断身份、绕过导航策略,也不能保证每个浏览器版本都支持同一 Navigation API。浏览器事件是当前文档的一次观察,不是查看用户完整浏览历史的权限。
要点
- WICG Navigation API 为同文档 URL 变化和支持的跨文档提交提供结构化观察点。
navigate、currententrychange和 transition promise 处于不同阶段,必须记录时序,不能把事件直接当成提交。navigation.currentEntry与history.state只代表当前文档的会话历史条目,不是跨来源历史数据库。- 夹具应分开测试同文档、跨文档和
window.navigation不可用时的回退。 - BotBrowser 重复声明的旅程并保留有限证据,不绕过策略,也不把过渡变成身份结论。
目录
Navigation API 观察什么
WICG Navigation API 规范 将导航建模为带目的 URL、类型、激活上下文和过渡的操作。片段变化或 history.pushState() 可以保持文档并改变活动历史条目;跨文档导航最终替换文档,旧页面不能在卸载后继续读取新页面。MDN 的 Navigation API 页面有助于支持判断,但支持面会变化,因此要在夹具中检查 window.navigation、目标事件和回退行为。
navigate 事件可以观察或拦截符合条件的导航,event.intercept() 和 event.transitionWhile() 让应用把渲染工作关联到过渡。测试应记录拦截是否接受、promise 是否完成,而不是把 pending 当成提交。WHATWG HTML 历史模型 仍是基础:会话历史条目有 URL 和可选状态,遍历会激活条目。
历史条目与隐私边界
navigation.currentEntry 的 id、url 和 getState(),以及 history.state,只帮助当前来源恢复本地界面状态。它们不会返回完整用户历史、私密浏览记录或其他来源的条目。不要把令牌、邮箱和客户记录放入 pushState();使用短路由键,并在授权后获取数据。状态也可能被当前来源脚本或应用日志复制,所以应视为受控应用数据,而不是身份凭据。
同源是脚本访问边界。当前文档可以观察自己的条目;跨来源目标运行自己的文档,源页面不能读取它的状态。服务器日志、Referer、Cookie 和应用参数是独立通道,不能从一个过渡事件推断出来。相同 URL 也可能对应不同 entry ID,因此不要把 URL 等同一次访问或一个人。
事件时序与过渡时间
navigate 是观察或拦截机会;成功的同文档操作可能随后触发 currententrychange,而跨文档操作可能先卸载旧页面。导航类型、拦截和浏览器实现会影响顺序。使用单调时间记录事件名、脱敏路径、entry ID 和 promise 结果。transitionWhile() 完成只说明客户端工作完成,不说明 API 或支付成功;网络断言必须独立验证。后退和前进也要单测,因为遍历可能恢复旧条目而不创建文档。
受控夹具与回退
下面的 Playwright 风格片段使用合成路径,记录事件但不记录 Cookie、授权头或客户 URL:
const events = [];
const log = name =>
events.push({
name,
atMs: Math.round(performance.now()),
entryId: window.navigation?.currentEntry?.id ?? null,
path: new URL(location.href).pathname,
});
if (window.navigation) {
navigation.addEventListener('navigate', event => log('navigate'));
navigation.addEventListener('currententrychange', event => log('currententrychange'));
}
history.pushState({ route: 'synthetic-a' }, '', '/fixture/a');
log('after-push');
await page.getByRole('link', { name: 'cross-document' }).click();
console.log(events);
当 API 或拦截不可用时,使用普通链接和 popstate 恢复同文档状态,并让浏览器完成跨文档导航。成功标准是产品不变量保持,例如路由标签和授权视图恢复,而不是复制所有内部事件。记录所用模式和浏览器版本。
证据决策表
| 观察 | 稳妥解释 | 不应声称 | 下一步 |
|---|---|---|---|
同源更新前触发 navigate | 当前文档观察到可处理导航 | 服务器已提交或识别用户 | 记录目的路径和结果 |
| entry ID 改变 | 活动历史条目改变 | 一定加载了新文档 | 分开检查状态和生命周期 |
| transition promise 完成 | 客户端工作完成 | API 或支付成功 | 单独断言网络结果 |
没有 window.navigation | 本次需要兼容路径 | 所有浏览器都不兼容 | 执行链接与 popstate 回退 |
| 跨来源目标加载 | 浏览器完成导航 | 目标能读源历史 | 用合成来源验证隔离 |
BotBrowser 的能力是按声明的浏览器、平台、代理和配置重复夹具并保存有限过渡与历史观察;限制是不能绕过策略、读取其他来源历史、强行启用不支持事件、推断身份或证明服务器业务结果。
结论
把 Navigation API 当作当前浏览上下文的结构化观察面。分离同文档状态变化与跨文档提交,用时间戳记录事件顺序,并在特性检测失败时执行真实回退。历史状态保持合成且最小化,证据只说明当前文档观察到什么、不能观察什么以及使用了哪条兼容路径。