跳到主要内容

Beacon API

为了把尽量多的页面信息传到服务器,很多分析工具需要在页面生命周期中尽量晚的时候向服务器 发送遥测或分析数据。因此,理想的情况下是通过浏览器的 unload 事件发送网络请求。这个事件表示 用户要离开当前页面,不会再生成别的有用信息了。

unload 事件触发时,分析工具要停止收集信息并把收集到的数据发给服务器。这时候有一个问题, 因为 unload 事件对浏览器意味着没有理由再发送任何结果未知的网络请求(因为页面都要被销毁了)。 例如,在 unload 事件处理程序中创建的任何异步请求都会被浏览器取消。为此,异步 XMLHttpRequest 或 fetch() 不适合这个任务。分析工具可以使用同步 XMLHttpRequest 强制发送请求,但这样做会导 致用户体验问题。浏览器会因为要等待 unload 事件处理程序完成而延迟导航到下一个页面。

为解决这个问题,W3C 引入了补充性的 Beacon API。这个 API 给 navigator 对象增加了一个 sendBeacon() 方法。这个简单的方法接收一个 URL 和一个数据有效载荷参数,并会发送一个 POST 请求。可选的数据有效载荷参数有 ArrayBufferViewBlobDOMStringFormData 实例。如果请 求成功进入了最终要发送的任务队列,则这个方法返回 true,否则返回 false。

// 发送 POST 请求
// URL: 'https://example.com/analytics-reporting-url'
// 请求负载:'{foo: "bar"}'

navigator.sendBeacon(
'https://example.com/analytics-reporting-url',
'{foo: "bar"}',
);

这个方法虽然看起来只不过是 POST 请求的一个语法糖,但它有几个重要的特性。

  • sendBeacon() 并不是只能在页面生命周期末尾使用,而是任何时候都可以使用。
  • 调用 sendBeacon() 后,浏览器会把请求添加到一个内部的请求队列。浏览器会主动地发送队列中的请求。
  • 浏览器保证在原始页面已经关闭的情况下也会发送请求。
  • 状态码、超时和其他网络原因造成的失败完全是不透明的,不能通过编程方式处理。
  • 信标(beacon)请求会携带调用 sendBeacon() 时所有相关的 cookie。