📡 前端错误监控从零搭建:window.onerror 与 unhandledrejection 的完整实践

问题场景

线上用户反馈"页面白屏了",你本地怎么复现都不行;或者用户说"点按钮没反应",但你根本不知道报了什么错。没有错误监控的前端,就像蒙着眼睛开车------全靠用户当你的眼睛。

原因分析

前端错误主要分三类,捕获方式完全不同:

  1. 运行时错误 (同步/异步代码抛错)→ window.onerror
  2. Promise 未捕获拒绝 → unhandledrejection
  3. 资源加载失败 (图片/脚本/CSS)→ error 事件的捕获阶段

很多人只监听 window.onerror,结果 Promise 错误和资源错误全漏了。

完整监控方案

第一步:捕获运行时错误

js 复制代码
window.onerror = function (message, source, lineno, colno, error) {
  report({
    type: 'runtime',
    message,
    source,
    lineno,
    colno,
    stack: error?.stack,
    url: location.href,
    ua: navigator.userAgent,
    time: Date.now()
  });
  // 注意:返回 true 会阻止浏览器默认处理(如控制台报错),慎用
};

第二步:捕获 Promise 错误(最容易漏)

js 复制代码
window.addEventListener('unhandledrejection', (e) => {
  // e.reason 可能是 Error 对象,也可能是任意值(如字符串、对象)
  report({
    type: 'promise',
    message: e.reason?.message || String(e.reason),
    stack: e.reason?.stack,
    time: Date.now()
  });
  e.preventDefault(); // 可选:屏蔽控制台红色警告
});

第三步:捕获资源加载失败

js 复制代码
// 必须用捕获阶段(第三个参数 true),因为资源错误不会冒泡
window.addEventListener('error', (e) => {
  const target = e.target;
  if (target && (target.tagName === 'IMG' || target.tagName === 'SCRIPT' || target.tagName === 'LINK')) {
    report({
      type: 'resource',
      tag: target.tagName,
      src: target.src || target.href,
      time: Date.now()
    });
  }
}, true);

第四步:框架层兜底

Vue 3:

js 复制代码
app.config.errorHandler = (err, instance, info) => {
  report({ type: 'vue', message: err.message, stack: err.stack, info });
};

React: 用 Error Boundary 包裹,componentDidCatch 里上报。

第五步:上报策略(防刷爆后端)

js 复制代码
// 采样 + 去重 + 批量
let buffer = [];
function report(data) {
  buffer.push(data);
  if (buffer.length >= 10) flush();
}
function flush() {
  if (!buffer.length) return;
  // 用 sendBeacon,页面关闭也能发出;且不阻塞主线程
  navigator.sendBeacon('/api/error-report', JSON.stringify(buffer));
  buffer = [];
}
window.addEventListener('beforeunload', flush);

// 采样:只上报 10% 的重复错误,控制成本
if (Math.random() > 0.1) return;

进阶技巧

  • sourcemap 还原 :生产代码是压缩的,上报 error.stack 后,用 sourcemap 在服务端还原原始行号(webpack 配 devtool: 'hidden-source-map',map 文件不上传到 CDN)
  • 错误去重 :同一错误一天内只告警一次,按 message + source + lineno 做指纹
  • 白屏检测 :document.readyState 长时间非 complete 或 document.body 无子节点,主动上报

要点总结

  • 三类错误三种捕获姿势:onerror(运行时)、unhandledrejection(Promise)、捕获阶段 error(资源)
  • 框架错误要用各自的钩子(Vue errorHandler / React Error Boundary)
  • sendBeacon + 批量上报,页面销毁也不丢数据
  • 采样、去重、指纹告警,否则监控系统会被错误洪流淹没
  • sourcemap 只上线 map 文件到内网,别把源码泄露到 CDN
相关推荐
仿生狮子3 小时前
OpenAI 攻下千禧年难题之后,开发者似乎无动于衷
前端·数学·vibecoding
Lvan的前端笔记6 小时前
docker:每个前端项目一个 Nginx 容器还是只有一个Nginx容器
前端·nginx·docker
三天不学习7 小时前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
xcs194057 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
明月_清风8 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
Csvn9 小时前
框架性能优化
前端
回眸&啤酒鸭11 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138411 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员11 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子11 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端