错误上报方式
前端错误上报的两种常用方式:Image Beacon 和 sendBeacon
问题
前端错误上报有哪两种常用方式?各有什么特点?
解答
方式一:Image Beacon(图片打点)
// 使用 Image 对象发送上报请求
function reportByImage(url, data) {
const img = new Image();
// 将数据拼接到 URL 参数中
const params = Object.keys(data)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
.join('&');
img.src = `${url}?${params}`;
}
// 使用示例
reportByImage('https://log.example.com/report', {
type: 'error',
message: 'Uncaught TypeError',
page: location.href,
timestamp: Date.now()
});
方式二:Navigator.sendBeacon
// 使用 sendBeacon 发送上报请求
function reportByBeacon(url, data) {
// sendBeacon 支持发送 Blob、FormData、字符串等
const blob = new Blob([JSON.stringify(data)], {
type: 'application/json'
});
// 返回 boolean,表示是否成功加入发送队列
return navigator.sendBeacon(url, blob);
}
// 使用示例
reportByBeacon('https://log.example.com/report', {
type: 'error',
message: 'Uncaught TypeError',
page: location.href,
timestamp: Date.now()
});
完整的错误上报封装
class ErrorReporter {
constructor(reportUrl) {
this.url = reportUrl;
}
// 优先使用 sendBeacon,降级使用 Image
report(data) {
const payload = {
...data,
timestamp: Date.now(),
url: location.href,
userAgent: navigator.userAgent
};
// 优先使用 sendBeacon
if (navigator.sendBeacon) {
const blob = new Blob([JSON.stringify(payload)], {
type: 'application/json'
});
const success = navigator.sendBeacon(this.url, blob);
if (success) return;
}
// 降级使用 Image
const img = new Image();
img.src = `${this.url}?data=${encodeURIComponent(JSON.stringify(payload))}`;
}
}
// 使用
const reporter = new ErrorReporter('https://log.example.com/report');
// 监听全局错误
window.onerror = function(message, source, lineno, colno, error) {
reporter.report({
type: 'runtime',
message,
source,
lineno,
colno,
stack: error?.stack
});
};
// 监听 Promise 未捕获错误
window.addEventListener('unhandledrejection', function(event) {
reporter.report({
type: 'promise',
message: event.reason?.message || String(event.reason),
stack: event.reason?.stack
});
});
关键点
- Image Beacon:兼容性好,不受跨域限制,但只能 GET 请求,数据量有限
- sendBeacon:异步非阻塞,页面卸载时也能可靠发送,支持 POST
- sendBeacon 优势:不会延迟页面卸载,不影响下一个页面的加载性能
- 降级策略:优先 sendBeacon,不支持时降级到 Image
- 两者都不需要处理响应:上报请求通常是”发完即忘”的单向通信
目录