前端代码异常日志收集与监控

📅 2026/7/26 18:02:49
前端代码异常日志收集与监控
前端代码异常日志收集与监控为什么我们需要异常监控想象一下你精心打造了一个电商网站用户正在下单时页面突然白屏或者按钮点击没反应。更糟糕的是你完全不知道发生了什么直到用户投诉或者默默流失。这就是前端异常监控存在的意义。前端代码运行在用户浏览器中环境千差万别不同浏览器、不同操作系统、网络波动、用户操作习惯等。没有异常监控开发者就像蒙着眼睛开车。通过日志收集和监控我们能- 快速发现线上问题- 定位错误发生的具体代码位置- 分析错误频率和影响范围- 在用户感知前修复问题## 常见的前端异常类型在开始实现监控系统前我们需要知道要抓什么。常见的前端异常包括1.JavaScript运行时错误语法错误、未定义变量、类型错误等2.资源加载错误图片、脚本、样式文件加载失败3.异步请求错误Ajax/Fetch请求超时、状态码异常4.Promise异常未捕获的Promise reject5.用户行为异常表单验证错误、无效操作## 实现基础的异常捕获我们先从最基础的window.onerror和window.addEventListener(error)开始。这两个API可以捕获绝大多数运行时错误。javascript// 基础异常捕获示例(function() { // 捕获未处理的JavaScript运行时错误 window.onerror function(message, source, lineno, colno, error) { console.log(捕获到异常:, { message, // 错误描述如 Uncaught TypeError: xxx is not a function source, // 出错文件URL lineno, // 行号 colno, // 列号 error // 错误对象包含堆栈信息 }); // 将错误信息发送到服务器 sendErrorToServer({ type: js_error, message: message, stack: error ? error.stack : , url: window.location.href, timestamp: Date.now() }); return true; // 阻止默认错误处理 }; // 捕获资源加载错误图片、脚本、样式等 window.addEventListener(error, function(event) { // 区分资源加载错误和JS错误 if (event.target ! window) { const target event.target; const errorInfo { type: resource_error, tagName: target.tagName, // 如 IMG, SCRIPT, LINK src: target.src || target.href, // 资源地址 url: window.location.href, timestamp: Date.now() }; console.log(资源加载失败:, errorInfo); sendErrorToServer(errorInfo); } }, true); // 使用捕获阶段确保能捕获到资源错误 // 模拟发送错误到服务器 function sendErrorToServer(errorData) { // 使用Image对象发送兼容性好不受跨域限制 const img new Image(); img.src /log?data${encodeURIComponent(JSON.stringify(errorData))}; // 或者使用navigator.sendBeacon更现代的方式 if (navigator.sendBeacon) { navigator.sendBeacon(/log, JSON.stringify(errorData)); } }})();这段代码演示了如何捕获两种主要异常类型。注意window.addEventListener(error, handler, true)中的第三个参数true表示在捕获阶段处理事件这样能捕获到资源加载错误。而window.onerror主要用于JS运行时错误。## 处理Promise异常在现代前端开发中Promise无处不在。fetch请求、async/await等都会产生Promise。但window.onerror无法捕获未处理的Promise reject。javascript// Promise异常与Ajax请求监控(function() { // 捕获未处理的Promise reject window.addEventListener(unhandledrejection, function(event) { const reason event.reason; console.log(未处理的Promise拒绝:, reason); const errorInfo { type: promise_error, message: reason.message || String(reason), stack: reason.stack || , url: window.location.href, timestamp: Date.now() }; sendErrorToServer(errorInfo); // 阻止默认行为浏览器控制台输出错误 event.preventDefault(); }); // 监控Ajax/Fetch请求错误 const originalFetch window.fetch; window.fetch function() { const startTime Date.now(); const args arguments; // 返回一个新的Promise来包装原始fetch return originalFetch.apply(this, args) .then(response { // 记录成功的请求 const duration Date.now() - startTime; if (!response.ok) { // HTTP状态码不是2xx sendErrorToServer({ type: ajax_error, status: response.status, statusText: response.statusText, url: args[0], duration: duration, timestamp: Date.now() }); } return response; }) .catch(error { // 网络错误或超时 sendErrorToServer({ type: network_error, message: error.message, url: args[0], timestamp: Date.now() }); throw error; // 继续抛出让调用者处理 }); }; // 模拟发送日志 function sendErrorToServer(data) { // 实际项目中这里会使用批量发送、本地存储等策略 console.log([监控日志], data); // 使用Image打点确保不干扰主流程 const img new Image(); img.src /monitor?data${encodeURIComponent(JSON.stringify(data))}; } // 演示一个未处理的Promise // new Promise((resolve, reject) { // reject(new Error(测试Promise异常)); // }); // 演示fetch请求 // fetch(https://api.example.com/nonexistent) // .then(response response.json());})();注意我们覆盖了window.fetch这是一个常见的监控方式。但实际项目中更推荐使用观察者模式或事件总线来解耦避免直接修改原生API。另外对于XMLHttpRequest也需要类似的包装。## 日志上报策略直接发送每条错误日志会导致大量请求影响性能。我们需要考虑### 1. 批量上报javascriptclass ErrorReporter { constructor() { this.queue []; this.maxQueueSize 10; // 每10条上报一次 this.interval 5000; // 或每5秒上报一次 this.timer null; // 页面关闭前强制上报 window.addEventListener(beforeunload, () this.flush()); } add(error) { this.queue.push(error); if (this.queue.length this.maxQueueSize) { this.flush(); } else if (!this.timer) { this.timer setTimeout(() this.flush(), this.interval); } } flush() { if (this.queue.length 0) return; const data this.queue.slice(); this.queue []; clearTimeout(this.timer); this.timer null; // 使用sendBeacon或XHR发送 navigator.sendBeacon(/log/batch, JSON.stringify(data)); }}### 2. 采样上报对于高频错误可以按百分比采样比如只上报10%的用户错误。### 3. 本地缓存当网络不可用时将日志存储在localStorage或IndexedDB中恢复后补发。## 实践建议1.区分错误等级致命错误白屏、功能不可用需要立即告警信息错误如图片加载失败可以延迟处理。2.用户行为追踪记录错误发生前的用户操作序列方便复现问题。3.环境信息上报时附带浏览器版本、操作系统、屏幕分辨率等。4.去重机制相同错误只告警一次避免告警风暴。5.隐私保护不要收集用户密码、身份证等敏感信息。## 总结前端异常监控不是可选项而是现代Web应用的必备基础设施。通过window.onerror、window.addEventListener(error)和unhandledrejection这三个核心API我们能捕获绝大多数运行时错误。结合资源加载监控和网络请求监控基本覆盖了所有常见异常场景。实际项目中建议使用成熟的监控方案如Sentry、Fundebug等它们提供了更完善的功能堆栈解析、源码映射、性能监控、告警规则等。如果团队有特殊需求也可以基于本文的原理自建轻量级监控系统。记住没有监控的系统就像没有仪表盘的飞机——你永远不知道下一秒会发生什么。从今天开始为你的前端项目加上异常监控吧