📡 前端错误监控从零搭建: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 长时间非 completedocument.body 无子节点,主动上报

要点总结

  • 三类错误三种捕获姿势:onerror(运行时)、unhandledrejection(Promise)、捕获阶段 error(资源)
  • 框架错误要用各自的钩子(Vue errorHandler / React Error Boundary)
  • sendBeacon + 批量上报,页面销毁也不丢数据
  • 采样、去重、指纹告警,否则监控系统会被错误洪流淹没
  • sourcemap 只上线 map 文件到内网,别把源码泄露到 CDN
相关推荐
FreeTinker4 小时前
HTML本地存储技术解析:localStorage与sessionStorage的原理、差异与应用场景
前端·html
qq_452396234 小时前
第十二篇:《全链路监控与可观测性:前端错误追踪与性能分析》
前端
wangruofeng5 小时前
Phosphor Icons 官网源码拆解:URL 即存储、水波动画与 7362 Star 图标库的架构实践
前端·架构·github
BigTopOne5 小时前
WebRTC Native / Android 开发学习资源整理
前端
excel6 小时前
nuxt 3 升级 nuxt 4 报错之 hasInjectionContext
前端
何以解忧,唯有..7 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
软件聚导航8 小时前
「聚小软 AI 助手」技术升级:从数据库检索到 RAG 知识库问答
前端·数据库·mysql·微信小程序·小程序·ai编程·rag
恋猫de小郭8 小时前
看懂大模型架构术语,帮助你理解目前常见的大模型开源架构
前端·人工智能·ai编程
yma168 小时前
通过提示词实现GitHub Pages 和 Nginx 双部署竟然这么简单?
前端
前端 贾公子8 小时前
第09章:上下文与记忆 (2)
java·服务器·前端