前端监控数据上报时,为什么用 navigator.sendBeacon 会失败?

Des.邦安 阅读 35

我在做前端错误监控,尝试用 navigator.sendBeacon 上报错误日志,但有时候数据根本没发出去,控制台也没报错,特别在页面快关闭的时候。我试过改成 fetchkeepalive: true,好像也不稳定。

这是我的上报代码:

function report(data) {
  const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
  navigator.sendBeacon('/log', blob);
}

是不是我哪里写错了?还是说 sendBeacon 有啥限制?比如请求头不能自定义之类的?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
志玉(打工版)
问题应该出在 navigator.sendBeacon 的使用场景上。sendBeacon 设计初衷是为了在页面卸载时发送数据,并且它会在后台自动处理请求,因此对请求头的自定义支持有限。此外,如果浏览器在 sendBeacon 发起后立即关闭,请求可能无法完成。

你提到的 fetch 加 keepalive: true 在某些情况下可能会比 sendBeacon 更可靠,但也有可能因为浏览器兼容性或者网络问题不稳定。

你的代码本身没有明显问题,但可以尝试以下改进:

1. 检查网络状态,确保在发送请求时网络是可达的。
2. 使用 fetch 作为 fallback,当 sendBeacon 失败时,使用 fetch 来发送数据。
3. 确保服务器端正确处理了请求,并返回了成功的响应。

下面是改进后的代码示例:

pre class="pure-highlightjs line-numbers">function report(data) {
const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });

// 尝试使用 sendBeacon
if (navigator.sendBeacon) {
navigator.sendBeacon('/log', blob);
} else {
// 如果 sendBeacon 不可用,则使用 fetch
fetch('/log', {
method: 'POST',
body: blob,
keepalive: true
}).catch(error => {
console.error('Failed to send data with fetch:', error);
});
}
}


这样可以提高数据上报的成功率。不过也要注意,即使这样处理,也无法保证 100% 成功,因为网络环境是不可控的。
点赞
2026-03-22 20:23
UE丶晴文
代码没大问题,但 sendBeacon 确实有限制,不能自定义请求头,而且你的 Blob type 设置成 application/json 后端不一定能正确解析,因为 sendBeacon 实际发出的 Content-Type 可能被浏览器忽略或改掉。

最稳的做法是这样写:

function report(data) {
const blob = new Blob([JSON.stringify(data)], { type: 'text/plain' });
const success = navigator.sendBeacon('/log', blob);
if (!success) {
// 队列满了,降级处理
fetch('/log', { method: 'POST', body: blob, keepalive: true });
}
}


后端记得兼容 text/plain 自己解析 JSON,或者干脆用 fetch + keepalive,这个能自定义 headers。还有 sendBeacon 有数据大小限制大概 64KB,超出也会失败。
点赞 2
2026-02-28 20:08