如何利用 navigator.sendBeacon 确保页面关闭瞬间依然能可靠发送埋点分析数据

作者:袖梨 2026-07-21
navigator.sendBeacon 关键在于由浏览器后台线程在卸载后尽力发送,应监听 pagehide 事件(排除 bfcache 场景),传 Blob 或 URLSearchParams 数据,遵守同源与大小限制,不依赖响应,并对旧浏览器降级为 Image 打点。

navigator.sendBeacon 发送埋点数据,关键不是“关页面那一瞬发出去”,而是让浏览器接管发送时机——它会在页面卸载后、进程退出前,由后台线程尽力完成传输。只要调用成功(返回 true),浏览器就承诺尝试送达,不卡界面、不丢上下文。

选对事件:优先监听 pagehide,而非 unload 或 beforeunload

pagehide 是最稳妥的触发点:它在页面真正不可见时触发(包括刷新、跳转、关闭、进入 bfcache),且所有现代浏览器(含 iOS Safari)都支持良好。unload 在移动端常被忽略;beforeunload 会强制弹窗、无法获知用户选择,还可能被禁用。

  • 监听 pagehide,检查 event.persisted === false 再发送——若为 true,说明页面进了往返缓存(bfcache),并未真正离开,通常无需上报
  • 避免在 beforeunload 中调用 sendBeacon,该事件本意是让用户确认是否离开,不适合做异步数据上报

构造合适的数据:用 Blob 或 URLSearchParams,别直接传对象

sendBeacon 只接受 ArrayBufferViewBlobDOMStringFormData。直接传 JS 对象会失败;用 JSON.stringify() 得到字符串虽可行,但服务端需明确按 text/plain 解析。更推荐:

  • new Blob([JSON.stringify(data)], {type: 'application/json'}) —— 后端能按标准 JSON 处理
  • 或用 new URLSearchParams(data)(data 是键值对对象)—— 自动设为 application/x-www-form-urlencoded,兼容性极佳
  • 避免 FormData,除非真要上传文件;它会带 boundary,增加体积且部分后端解析麻烦

确保请求可达:注意同源与大小限制

sendBeacon 遵守同源策略,目标 URL 必须与当前页面同协议、域名、端口。跨域需后端配 CORS,但 sendBeacon 本身不触发预检,所以只支持简单请求(如 POST + text/plainapplication/x-www-form-urlencoded)。

  • 单次数据建议控制在 64KB 以内(Chrome 实测上限约 256KB,但 Safari 和旧版 Android 更严)
  • 埋点字段精简:去掉冗余字段,用短 key(如 pg 代替 page),时间戳用毫秒整数而非 ISO 字符串
  • 不要依赖响应:sendBeacon 没有回调,也无法读取状态码;服务端收到即记录,前端不做重试逻辑

兜底兼容:检测 API 存在性,旧环境降级处理

IE 完全不支持,部分老旧 Android 浏览器也缺失。可加一层判断,降级为 Image 像素打点(仅 GET,适合极简日志)或同步 XHR(仅作最后保障,慎用):

  • 先判断 if ('sendBeacon' in navigator),成立则走主流程
  • 否则尝试 new Image().src = '/log?' + new URLSearchParams(data),适合无敏感内容、低精度统计
  • 避免在生产环境使用同步 XHR,它会冻结 UI,Chrome 已限制其在 unload 中的行为

相关文章

精彩推荐