aurora blog
  • JS

    • 基本汇总
    • Date时间
    • Array方法
    • String 方法
    • Object方法
    • RegExp正则
    • Es6 新特性等
    • Event-Loop
    • Http and Https
    • for in和for of区别
    • Web Worker
    • Promise && async
    • 堆内存 & 栈内存
    • JS设计模式探索
    • npm & yarn
    • Fetch和Axios的区别
    • 学习及面试问题整理
    • URL 输入到页面加载过程
    • 跨域&nginx本地项目代理
  • FE框架

    • react

      • 基本用法
      • react生命周期
      • hooks 16.8版本后
      • Route原理
      • Redux源码解析
      • React16 Fiber
      • React-VirtualDOM
      • React事件委托机制
      • React性能优化
      • 状态管理方案对比
      • React 18新特性
    • vue

      • vue 基本用法
      • vue 生命周期
      • VirtualDOM
      • vue 事件委托
      • vue 架构
      • vue 状态管理
      • 问题等
    • React-Native

      • React-Native 基本用法
    • 微前端

      • 遇到的问题
    • 鸿蒙 harmony

      • harmony 基础
  • 构建工具

    • webpack

      • Webpack配置详解
      • Webpack的使用
      • Babel-polyfill
      • webpack面试题
    • vite

      • vite配置详解
      • vite面试题
    • rollup

      • Rollup配置详解
      • rollup面试题
    • 构建工具对比
  • 性能优化

    • 性能优化策略
    • 缓存策略
    • 性能优化面试题
  • 浏览器

    • 浏览器渲染原理
    • 浏览器缓存机制
    • 浏览器面试题
  • 工程化

    • 代码规范
    • 工程化面试题
  • 前端安全

    • XSS 攻击与防护
    • CSRF 攻击与防护
    • 前端安全面试题
  • 移动端开发

    • 移动端适配
    • 移动端开发面试题
  • 前端监控

    • 错误监控
    • 性能监控
    • 前端监控面试题
  • Typescript

    • Typescript详解
  • Servers

    • Nodejs
    • Nginx
  • Git命令

    • git常用规范
  • 数据库

    • mongodb
    • mongodb
  • Other

    • Jenkins自动化部署

错误监控

  • 错误监控概述
  • 错误类型
    • 1. JavaScript 错误
    • 2. 资源加载错误
    • 3. 网络错误
  • 错误捕获
    • 1. window.onerror
    • 2. unhandledrejection
    • 3. 资源加载错误
    • 4. Vue 错误捕获
    • 5. React 错误捕获
  • 错误上报
    • 1. 基础上报
    • 2. 批量上报
    • 3. Source Map
  • 监控平台
    • 1. Sentry
    • 2. 自建监控
  • 错误分析
    • 1. 错误统计
    • 2. 错误分组
    • 3. 错误定位
  • 最佳实践
    • 1. 错误捕获
    • 2. 错误上报
    • 3. 错误分析
    • 4. 用户体验

错误监控概述

前端错误监控是保障应用稳定性的重要手段,主要包括:

  • 错误捕获:JavaScript 错误、资源加载错误
  • 错误上报:发送到监控平台
  • 错误分析:统计、分析、定位问题

错误类型

1. JavaScript 错误

语法错误:

// 语法错误,无法捕获
const x = ; // SyntaxError

运行时错误:

// 运行时错误,可以捕获
undefined.foo(); // TypeError

异步错误:

// Promise 错误
Promise.reject('error').catch(err => {
  console.error(err);
});

// async/await 错误
async function test() {
  try {
    await Promise.reject('error');
  } catch (err) {
    console.error(err);
  }
}

2. 资源加载错误

图片加载错误:

img.onerror = function() {
  console.error('Image load failed');
};

脚本加载错误:

script.onerror = function() {
  console.error('Script load failed');
};

3. 网络错误

AJAX 错误:

fetch('/api/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network error');
    }
    return response.json();
  })
  .catch(error => {
    console.error('Fetch error:', error);
  });

错误捕获

1. window.onerror

全局错误捕获:

window.onerror = function(message, source, lineno, colno, error) {
  console.error('Error:', {
    message,    // 错误信息
    source,     // 错误文件
    lineno,     // 行号
    colno,      // 列号
    error,      // 错误对象
  });
  
  // 上报错误
  reportError({
    message,
    source,
    lineno,
    colno,
    stack: error?.stack,
  });
  
  return true; // 阻止默认错误处理
};

限制:

  • 无法捕获 Promise 错误
  • 无法捕获资源加载错误
  • 跨域脚本错误信息不完整

2. unhandledrejection

Promise 错误捕获:

window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled rejection:', event.reason);
  
  // 上报错误
  reportError({
    type: 'unhandledrejection',
    reason: event.reason,
    stack: event.reason?.stack,
  });
  
  event.preventDefault(); // 阻止默认错误处理
});

3. 资源加载错误

捕获资源加载错误:

window.addEventListener('error', (event) => {
  // 区分资源加载错误和 JS 错误
  if (event.target !== window) {
    console.error('Resource load error:', {
      tag: event.target.tagName,
      url: event.target.src || event.target.href,
    });
    
    // 上报错误
    reportError({
      type: 'resource',
      tag: event.target.tagName,
      url: event.target.src || event.target.href,
    });
    
    return true;
  }
}, true); // 使用捕获阶段

4. Vue 错误捕获

全局错误处理:

Vue.config.errorHandler = (err, vm, info) => {
  console.error('Vue error:', {
    error: err,
    component: vm,
    info,
  });
  
  reportError({
    type: 'vue',
    error: err.toString(),
    stack: err.stack,
    info,
  });
};

5. React 错误捕获

Error Boundary:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error, errorInfo) {
    console.error('React error:', error, errorInfo);
    
    reportError({
      type: 'react',
      error: error.toString(),
      stack: error.stack,
      componentStack: errorInfo.componentStack,
    });
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    
    return this.props.children;
  }
}

错误上报

1. 基础上报

简单上报:

function reportError(errorInfo) {
  const data = {
    ...errorInfo,
    url: window.location.href,
    userAgent: navigator.userAgent,
    timestamp: Date.now(),
  };
  
  // 使用 sendBeacon(页面卸载时也能发送)
  if (navigator.sendBeacon) {
    navigator.sendBeacon('/api/error', JSON.stringify(data));
  } else {
    // 降级方案:使用 Image
    const img = new Image();
    img.src = `/api/error?data=${encodeURIComponent(JSON.stringify(data))}`;
  }
}

2. 批量上报

收集错误,批量上报:

class ErrorCollector {
  constructor() {
    this.errors = [];
    this.timer = null;
  }
  
  collect(error) {
    this.errors.push({
      ...error,
      timestamp: Date.now(),
    });
    
    // 达到阈值立即上报
    if (this.errors.length >= 10) {
      this.report();
    } else {
      // 延迟上报
      this.scheduleReport();
    }
  }
  
  scheduleReport() {
    if (this.timer) {
      clearTimeout(this.timer);
    }
    
    this.timer = setTimeout(() => {
      this.report();
    }, 5000); // 5秒后上报
  }
  
  report() {
    if (this.errors.length === 0) return;
    
    const data = this.errors.slice();
    this.errors = [];
    
    fetch('/api/errors', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    }).catch(err => {
      console.error('Report failed:', err);
      // 失败后重新加入队列
      this.errors.unshift(...data);
    });
  }
}

3. Source Map

使用 Source Map 定位错误:

function reportError(errorInfo) {
  // 发送错误信息
  fetch('/api/error', {
    method: 'POST',
    body: JSON.stringify({
      ...errorInfo,
      // 包含 Source Map 信息
      sourceMap: true,
    }),
  });
}

// 服务端使用 source-map 库解析
// const sourceMap = require('source-map');
// const consumer = await new sourceMap.SourceMapConsumer(map);
// const original = consumer.originalPositionFor({ line, column });

监控平台

1. Sentry

集成:

import * as Sentry from '@sentry/browser';

Sentry.init({
  dsn: 'https://xxx@sentry.io/xxx',
  environment: 'production',
  beforeSend(event) {
    // 过滤敏感信息
    if (event.user) {
      delete event.user.email;
    }
    return event;
  },
});

// 手动上报
Sentry.captureException(error);

2. 自建监控

服务端接口:

// Express
app.post('/api/error', (req, res) => {
  const errorInfo = req.body;
  
  // 存储错误
  saveError(errorInfo);
  
  // 发送告警
  if (isCritical(errorInfo)) {
    sendAlert(errorInfo);
  }
  
  res.json({ success: true });
});

错误分析

1. 错误统计

统计维度:

  • 错误类型
  • 错误频率
  • 影响用户数
  • 错误趋势

2. 错误分组

分组规则:

  • 错误信息相同
  • 错误堆栈相同
  • 错误文件相同

3. 错误定位

定位信息:

  • 错误文件
  • 错误行号
  • 错误堆栈
  • 用户操作路径

最佳实践

1. 错误捕获

  • 全局错误捕获
  • Promise 错误捕获
  • 资源加载错误捕获
  • 框架错误捕获

2. 错误上报

  • 使用 sendBeacon
  • 批量上报
  • 失败重试
  • 过滤敏感信息

3. 错误分析

  • 错误统计
  • 错误分组
  • 趋势分析
  • 告警机制

4. 用户体验

  • 错误提示
  • 降级方案
  • 错误恢复
  • 用户反馈
最近更新:: 2025/11/20 14:50
Contributors: liyulai
Next
性能监控