前端监控数据批量上报怎么避免重复发送?

翌菡 Dev 阅读 5

我在做前端性能监控,想把用户行为日志攒一批再统一发到后端,但发现有时候页面快关了还没发出去,就用 beforeunload 补发。结果偶尔会看到同一条日志被上报两次,是不是因为正常上报和 beforeunload 触发重叠了?

我现在的逻辑大概是这样的:

let logs = [];

function addLog(log) {
  logs.push(log);
  if (logs.length >= 10) {
    sendLogs();
  }
}

function sendLogs() {
  if (logs.length === 0) return;
  fetch('/report', { method: 'POST', body: JSON.stringify(logs) })
    .then(() => logs = []);
}

window.addEventListener('beforeunload', () => {
  if (logs.length > 0) {
    // 这里用同步请求确保发出
    navigator.sendBeacon('/report', JSON.stringify(logs));
  }
});

但好像 sendLogs()beforeunload 里的 sendBeacon 会同时触发,导致重复。该怎么处理才安全?

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
Designer°秀英
我之前踩过这个坑,确实是因为正常上报和 beforeunload 事件触发重叠导致重复上报。要解决这个问题,关键是要保证在发送请求时加个标记,避免重复发送。

最简单的办法是在 sendLogs 函数里加个正在发送的标志位。比如这样改:

let logs = [];
let isSending = false;

function addLog(log) {
logs.push(log);
if (logs.length >= 10 && !isSending) {
sendLogs();
}
}

function sendLogs() {
if (logs.length === 0 || isSending) return;

isSending = true;
fetch('/report', { method: 'POST', body: JSON.stringify(logs) })
.then(() => {
logs = [];
isSending = false;
})
.catch(err => {
isSending = false;
console.error('上报失败', err);
});
}

window.addEventListener('beforeunload', () => {
if (!isSending && logs.length > 0) {
navigator.sendBeacon('/report', JSON.stringify(logs));
}
});


这个改动的核心是用 isSending 来防止重复请求。我还建议你在后端也做个去重处理,毕竟前端不可控因素太多,多个保险总没错。这种日志上报的坑真不少,我都踩麻了。
点赞
2026-03-29 15:14