前端错误捕获和上报的实践指南

2,189 阅读6分钟

本文正在参加「金石计划」

前言

当产品出现问题的时候,我们要做的就是快速定位问题所在并且解决,所以错误捕获和上报是非常重要的一环。尤其是运行在客户端的前端代码,如果不及时捕获和上报错误,不仅会给用户带来不良的体验,同时也会增加给开发人员分析问题的难度。因此,前端错误捕获和上报是前端开发中必不可少的一环。

本文将会介绍前端错误的分类,错误捕获和上报的方式以及错误处理的流程。希望通过本文可以帮助大家更好地处理前端错误,提高前端应用的质量和用户体验。

前端错误分类

在前端开发中,错误可以分为以下几种(不同类型的错误需要采用不同的错误捕获方式):

image-20230408212350264

常见报错提示

语法错误

  • SyntaxError
Uncaught SyntaxError: Invalid or unexpected token

运行错误

  • 变量引用错误,ReferenceError

    Uncaught ReferenceError: xxx is not defined
    
  • 数组范围错误,RangeError

    Uncaught RangeError: Invalid array
    
  • 数据类型错误,TypeError

    Uncaught TypeError: xxx is not a function
    
  • URIError 对象使用错误

    当使用encodeURI或者decodeURI报错的时候会出现这个错误

错误捕获方式

try-catch语句

try {
  // 可能会抛出异常的代码
} catch (error) {
  // 处理异常的代码
}

try-catch语句可以用来捕获JavaScript代码中的语法错误和运行时错误。当代码块中的语句抛出异常时,程序会跳转到catch语句块,并执行相应的处理逻辑。

注意:try-catch语句适用于同步代码的错误捕获,如果代码块中存在异步代码,try-catch语句无法捕获异步代码中的错误。


window.onerror

捕获全局JS异常,包括同步和异步代码中的错误

window.onerror = function(message, source, lineno, colno, error) {
  // 处理错误的代码
}

window.onerror是一个全局的错误处理函数,可以用来捕获未被try-catch捕获的运行时错误。当JavaScript代码执行发生异常时,会自动触发window.onerror函数,并传递相应的错误信息。


window.addEventListener("error")

捕获静态资源加载错误

  • 可以捕获,图片、script、css加载的错误,
  • 不可以捕获,new Image错误和fetch错误
window.addEventListener('error', function (event) {
  // 处理错误
});

window提供的可以监听window对象上的error事件,与window.onerror不同,error事件监听器可以在页面中的任何元素上注册,以捕获特定元素中发生的错误。


Vue、React等框架提供的错误处理方法:


//Vue,在Vue里面出现的错误,不会直接被window.onerror捕获,而是会抛给Vue.config.errorHandler。
Vue.config.errorHandler = function(err, vm, info) {
  // 处理错误的代码
}

//React
React.ErrorBoundary = class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  componentDidCatch(error, info) {
    // 处理错误的代码
  }
  render() {
    if (this.state.hasError) {
      // 自定义错误提示
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
};

许多前端框架都提供了自己的错误处理方式。例如Vue和React都提供了全局错误处理函数,可以用来捕获框架内部的错误。

错误上报方式

手动上报

开发人员在代码中手动调用上报函数来将错误信息上报到指定的服务器,需要开发人员自己实现上报逻辑

Ajax通信的方式上报

会存在跨域错误,上报接口阻塞正常业务请求,对业务造成影响等问题。少用

利用Image对象上报

不会有跨域问题,不会影响正常业务。常用

  • 需要注意在拼接参数的时候,需要使用 encodeURIComponent 对值进行转移否则将 location.href 这类url作为值时会造成错误
  • 相比PNG/JPGgif的体积可以达到最小,采用1*1像素透明色来上报,不存储色彩空间数据,节约
//使用方式
 (new Image()).src='http:xxxxx'  //上报路径  
 
//示例
function parseJsonToString(dataJson) {
  if (!dataJson ) { dataJson = {} }
  var dataArr = Object.keys(dataJson).map(function(key) { return key + '=' + encodeURIComponent(dataJson[key]) })
  return dataArr.join('&')
}

const logGif = (params) => {
  const upload = parseJsonToString(params)
  const img = new Image(1,1)
  img.src = 'https://view-error?' + upload
}

Navigator.sendBeacon

sendbeacon主要就是用于将统计数据发送到 Web 服务器,没有跨域问题,也不会阻塞业务请求, 缺点就是兼容性不太好。(可以结合上面的Image方式使用)

navigator.sendBeacon(url, data);
- url:表示 data 将要被发送到的网络地址;
- data:将要发送的 ArrayBufferView 或 Blob, DOMString 或者 FormData 类型的数据。
- 返回值:当用户代理成功把数据加入传输队列时,sendBeacon() 方法将会返回 true,否则返回 false

使用示例

sendBeacon并不像XMLHttpRequest一样可以直接指定Content-Type,且不支持application/json等常见格式。data的数据类型必须是 ArrayBufferView 或 Blob, DOMString 或者 FormData 类型的。

sendBeacon MDN

// 请求数据string,自动设置Content-Type 为 text/plain
const reportData = (url, data) => {
  navigator.sendBeacon(url, data);
};

// Blob一般手动设置其MIME type,一般设置为 application/x-www-form-urlencoded
const reportData = (url, data) => {
  const blob = new Blob([JSON.stringify(data), {
    type: 'application/x-www-form-urlencoded',
  }]);
  navigator.sendBeacon(url, blob);
};

// 可以直接创建一个新的Formdata,请求头自动设置Content-Type为multipart/form-data
const reportData = (url, data) => {
  const formData = new FormData();
  Object.keys(data).forEach((key) => {
    let value = data[key];
    if (typeof value !== 'string') {
      // formData只能append string 或 Blob
      value = JSON.stringify(value);
    }
    formData.append(key, value);
  });
  navigator.sendBeacon(url, formData);
};

自动上报

无需开发人员干预,在代码中集成相应的错误上报插件或SDK,错误信息将自动上报到指定的服务器

一些常见的错误捕获库
- Sentry:一个流行的开源错误捕获和上报库,提供了完整的错误上报和跟踪功能。
- Bugsnag:另一个常用的错误捕获和上报库,提供了实时错误通知和可视化分析等功能。
- Raygun:一个专业的错误监测和分析平台,提供了多种编程语言的错误监测和分析功能。

集中式日志平台

集中式日志平台可以帮助我们集中管理和分析前端错误。开发人员只需要将错误信息上报到集中式日志平台,即可实现错误信息的集中管理和分析,但是需要开发人员自己搭建或者使用第三方的集中式日志平台

一些用于错误上报和分析的专业的监控系统,例如New Relic、AppDynamics和Datadog等。

错误处理流程

捕获错误,上报错误,分析错误,解决错误

image-20230408222646571

//捕获错误
try {
  // 可能会抛出异常的代码
} catch (error) {
  // 处理异常的代码
  handleError(error); // 处理错误
}

function handleError(error) {
  // 上报错误
  reportError(error);
  // 处理错误
  switch(error.type) {
    case 'SyntaxError':
      // 处理语法错误
      break;
    case 'ReferenceError':
      // 处理引用错误
      break;
    case 'TypeError':
      // 处理类型错误
      break;
    default:
      // 其他错误
      break;
  }
  // 解决错误
  fixError(error);
}

分析:

以上代码主要做了这几个事情:

  • 1)使用try-catch语句捕获前端错误。
  • 2)在catch语句块中调用了handleError函数进行错误处理。(在handleError函数中,我们首先将错误信息上报到指定的服务器。
  • 3)根据错误类型进行处理。(例如处理语法错误、引用错误、类型错误等等。最后,我们使用fixError函数对错误进行修复。


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 Vue的渲染函数render&h

👉 ES6中一些很好用的数组方法

👉 echarts | 柱状图实用配置

👉 JS设置获取盒模型对应宽高的五种方式详解