页面卸载时自定义上报请求被浏览器取消怎么办?

皇甫米娅 阅读 91

我在做页面性能监控时,想在页面关闭前上报用户停留时长。用了window.addEventListener('beforeunload')触发上报,但发现大部分请求都被浏览器取消了。尝试改用unload事件也不稳定,有时候数据完全没收到。

试过用AbortController控制请求,但发现页面关闭时信号量自动置为aborted。代码大致这样写的:


window.addEventListener('beforeunload', () => {
  fetch('/log', {
    method: 'POST',
    body: JSON.stringify({ duration: Date.now() - startTime }),
    headers: { 'Content-Type': 'application/json' }
  });
});

控制台报错说请求因页面卸载被取消了。有没有更可靠的上报方式?听说navigator.sendBeacon能解决这个问题,但不太清楚具体怎么用。

我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
小克样
小克样 Lv1
这个问题在规范里其实说得很清楚,传统的 XHR 和 fetch 在页面卸载时会被浏览器强制终止,因为规范允许浏览器在文档卸载过程中中止正在进行的网络请求。

你提到的 beforeunloadunload 事件都不靠谱,现代浏览器的 bfcache 机制还会让这些事件根本不触发。真正推荐的做法是用 navigator.sendBeacon(),这个 API 就是专门为这种场景设计的,它会把请求放入浏览器的发送队列,即使页面卸载了请求也能发出去。

基本用法是这样的:

window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/log', JSON.stringify({
duration: Date.now() - startTime,
url: location.href
}));
}
});


这里有几个细节要注意。第一,推荐监听 visibilitychange 事件并判断 hidden 状态,而不是 beforeunload,因为前者在移动端和现代浏览器的 bfcache 场景下更可靠,这是 Page Visibility Level 2 规范推荐的方式。第二,sendBeacon 只支持 POST 请求,发送的是 POST body,服务端需要按 POST 方式接收。第三,如果需要自定义请求头,比如设置 Content-Type 为 application/json,可以用 Blob 包装:

const blob = new Blob([JSON.stringify({ duration: Date.now() - startTime })], {
type: 'application/json'
});
navigator.sendBeacon('/log', blob);


另外 fetch API 在较新的浏览器里支持 keepalive 选项,功能和 sendBeacon 类似,也能保证请求在页面卸载后继续发送:

fetch('/log', {
method: 'POST',
body: JSON.stringify({ duration: Date.now() - startTime }),
headers: { 'Content-Type': 'application/json' },
keepalive: true
});


keepalive: true 的请求有 64KB 大小限制,超过会被浏览器拒绝,sendBeacon 也有同样的限制,不过对于监控上报来说完全够用。两种方式都可以,sendBeacon 兼容性更好一些,keepalive 写法更灵活,看你项目需要支持哪些浏览器吧。
点赞 1
2026-03-01 21:04
技术红彦
navigator.sendBeacon 替代 fetch,它专为页面卸载时可靠发送请求设计。
修改你的代码如下:

window.addEventListener('beforeunload', () => {
const data = JSON.stringify({ duration: Date.now() - startTime });
navigator.sendBeacon('/log', data);
});


确保后端用 Content-Type: application/json 解析请求体,就这样。
点赞 10
2026-02-06 17:50