前端异常捕获与上报

一、捕获的错误类型

  • 语法错误
  • 运行时异常
  • 资源加载异常
    • img
    • script
    • link
    • audio
    • video
    • iframe
    • ...外链资源的DOM元素
  • 异步请求异常
  • Promise异常
  • CSS中资源异常
    • font-face
    • background-image         

 

二、捕获方式

  • try-catch
  • window.onerror = cb (DOM0)
  • window.addEventListener('error', cb, true) (DOM2)
  • window.addEventListener("unhandledrejection", cb) (DOM4)
  • Promise.then().catch(cb)
  • 定制异步请求代码

 

三、错误上报相关问题

  • 获取不到具体错误
    • 跨域调用js,由于浏览器的安全策略,只会返回 Script error. ;通过添加crossorigin来解决; image 和 script 标签都有 crossorigin 参数,它的作用就是告诉浏览器,我要加载一个外域的资源,并且我信任这个资源;服务器也需要设置 Access-Control-Allow-Origin 的响应头;
    • 生产环境代码都被压缩打包,可以在打包代码时相应添加一些空格,虽然不能定位到具体位置,不过通过行数,可以获得具体哪个文件出了错,缩小排查范围;
  • 收集的采样率
    • 没有必要将所有的错误信息全部送到 Log 中,这个量太大了。如果网页 PV 有 1kw,那么一个必现错误发送的 log 信息将有 1kw 条,大约一个 G 的日志。我们可以给 Reporter 函数添加一个采样率;
      function needReport (sampling){
        // sampling: 0 - 1
        return Math.random() <= sampling;
      }
      Reporter.send = function(errInfo, sampling) {
        if(needReport(sampling || 1)){
          Reporter._send(errInfo);
        }
      };
  • 尽量少的使用try..catch,如果要使用请使用尽量干净的作用域;
  • 错误的报警与提示
    • 错误超过阈值,比如 10分钟最多允许 100 个错误,结果超过了 100
    • 错误超过平均值的 10 倍,超过平均值就报警,这个逻辑显然不正确,但是超过了平均值的 10 倍,基本可以认定服务出问题了
    • 在纳入对比之前,要过滤同 IP 出现的错误,比如一个错误出现在 for 循环或者 while 循环中,再比如一个用户在蹲点抢购,不停的刷新
  • 上报方式
    • 优点实现简单可跨域;
      // 简单可跨域
      function report() {
          (new Image()).src="http://post.error.com?data=xxx"
      }
      进阶版,使用 Navigator.sendBeacon()
    • // navigator.sendBeacon(url, data);
      navigator.sendBeacon('http://post.error.com', 'data=xxxxx');
      // data 可以传递 string 类型,那么后端接口里接到的请求,Content-Type 为 text/plain,就当字符串处理data
      // 此方法可用于满足统计和诊断代码的需要,可以批量发送数据,并且浏览器保证它不卡渲染线程,在页面 load/unload 事件里处理异步动作而不影响渲染,并且天然跨域。缺点只是兼容性了
    • 兼容版
      function reportData(url, data) {
          if (navigator.sendBeacon) {
              navigator.sendBeacon(url, data);
          } else {
              (new Image()).src = `${url}?data=${data}`
          }
      }
      export default reportData;  

 

  •  几种上报方法
    • window.addEventListener("error", function(e) {
          var eventType = [].toString.call(e, e);
          if (eventType === "[object Event]") { // 过滤掉运行时错误
            // 上报加载错误 可以获取资源加载错误
         console.log(ev.target);
           report(ev)
          } 
      }, true );    

       

    • window.onerror = function (msg, url, lineNo, columnNo, error) { 
         // 捕捉错误
         console.log(msg, url, lineNo, columnNo, error)
       }

       

    • window.addEventListener("unhandledrejection", function (event) {
          // 捕获违背catch的reject
          console.log(event)
          console.log(event.reason);
          event.preventDefault();
          // window.addEventListener('error')捕获资源加载错误。因为它也能捕获js运行时错误,为避免重复上报js运行时错误,此时只有event.srcElement inatanceof HTMLScriptElement或HTMLLinkElement或HTMLImageElement时才上报
      }); 

       

    • //window.onerror和window.addEventListener('error')的异同
      //相同点是都可以捕获到window上的js运行时错误。
      //区别是1.捕获到的错误参数不同 
      //     2.window.addEventListener('error')可以捕获资源加载错误,但是window.onerror不能捕获到资源加载错误

       

 

 

 

 

 ps: 感谢巨人的肩膀使我们看的更远

 

上一篇:JavaScript事件


下一篇:事件高级1注册事件(绑定事件)