设计一个前端监控系统捕获 JavaScript 错误,需围绕错误捕获、上下文收集、上报优化和堆栈还原四个核心环节展开,确保全面、稳定、低损耗地收集运行时异常。 以下是具体实现方案:
1. 全局错误捕获机制通过浏览器提供的全局事件监听,捕获未处理的同步/异步错误及资源加载问题,确保无遗漏。
- 同步错误:使用 window.onerror 捕获 JavaScript 运行时错误(如语法错误、引用错误),需处理跨域脚本错误(需配置 CORS 和 <script crossorigin> 属性)。window.onerror = function(message, source, lineno, colno, error) { reportError({ type: 'runtime', message: error?.message || message, stack: error?.stack, file: source, line: lineno, column: colno, url: location.href, userAgent: navigator.userAgent }); return true; // 阻止浏览器默认错误上报};
- 资源加载错误:通过 window.addEventListener('error') 捕获图片、脚本等资源加载失败(需检查 event.target.tagName 区分类型)。window.addEventListener('error', (event) => { if (event.target && (event.target.src || event.target.href)) { reportError({ type: 'resource', resourceType: event.target.tagName.toLowerCase(), src: event.target.src || event.target.href, url: location.href }); }}, true); // 捕获阶段设为 true 以监听资源错误
- Promise 异常:监听 unhandledrejection 事件捕获未处理的异步错误,避免静默失败。window.addEventListener('unhandledrejection', (event) => { reportError({ type: 'promise', message: event.reason?.message || 'Unknown promise rejection', stack: event.reason?.stack, url: location.href });});
2. 上下文信息收集附加用户环境、网络状态和页面行为数据,辅助快速定位问题根源。
- 设备信息:浏览器类型、版本、操作系统、屏幕分辨率。
- 网络状态:有效连接类型(如 4G、WiFi)、RTT 延迟(通过 navigator.connection)。
- 页面状态:当前 URL、Referrer、DOM 加载状态(document.readyState)。
- 自定义标记:用户 ID(匿名化)、路由路径、操作流程(如“点击提交按钮后”)。function getContext() { return { url: location.href, referrer: document.referrer, timestamp: Date.now(), viewport: `${window.innerWidth}x${window.innerHeight}`, connection: navigator?.connection?.effectiveType, readyState: document.readyState, custom: { userId: getAnonymousUserId(), // 示例:匿名化用户标识 route: getCurrentRoute() // 示例:当前路由路径 } };}
3. 错误上报与节流控制优化上报策略,避免频繁请求影响性能或丢失关键日志。
- 上报时机:
页面卸载前:使用 navigator.sendBeacon 发送数据,确保日志不因页面关闭丢失。
离线缓存:若 sendBeacon 不可用,通过 localStorage 暂存错误,下次页面加载时补发。
- 节流策略:
重复错误去重:相同错误 5 分钟内仅上报一次(通过哈希错误信息实现)。
采样率控制:高流量场景下按比例采集(如 10%),减少服务端压力。
function reportError(data) { const payload = JSON.stringify({ ...data, ...getContext() }); const errorHash = hashError(payload); // 示例:简单哈希函数 const lastReportTime = localStorage.getItem(`lastReport_${errorHash}`); if (!lastReportTime || Date.now() - lastReportTime > 5 * 60 * 1000) { if (navigator.sendBeacon) { navigator.sendBeacon('/log', payload); } else { fetch('/log', { method: 'POST', body: payload, keepalive: true }); } localStorage.setItem(`lastReport_${errorHash}`, Date.now()); }}
4. Source Map 还原堆栈生产环境使用压缩代码时,需通过 Source Map 还原原始堆栈信息。
- 构建配置:生成 Source Map 文件(如 Webpack 的 devtool: 'source-map'),并部署到私有服务器。
- 后台解析:监控系统接收错误后,根据文件名和行列号查询 Source Map,还原原始文件位置和代码片段。
- 安全控制:Source Map 不应公开访问,需通过鉴权接口(如内部 API)提供查询服务。
5. 扩展功能(逐步完善)- 错误聚合分析:按错误类型、页面路径、用户设备等维度聚合数据,识别高频问题。
- 实时报警:设置阈值(如某错误 1 小时内出现超过 100 次),触发邮件/短信报警。
- 用户反馈入口:在错误页面提供反馈按钮,收集用户描述的复现步骤。
总结:一个高效的前端监控系统需以“捕获全、上下文足、上报稳”为核心,优先实现基础错误捕获和上报,再逐步扩展分析功能。通过全局错误监听、上下文增强、节流上报和 Source Map 还原,可快速搭建起稳定可靠的监控体系,帮助开发者快速定位和修复问题。