前端系统异常监控 - 基础

主要分类
  • js报错
  • 自定义异常
  • 静态资源异常
  • 接口请求异常: 业务参数错误、超时、服务器500
综合处理的异常类型
  • 语法错误、代码异常
  • http请求异常
  • 静态资源加载异常
  • Promise运行异常
  • iframe异常
  • 跨域scriptError
  • 崩溃和卡顿
捕获异常的几种方法

1.try{}catch(e){}
可以捕获同步运行发生的错误,对异步和语法错误无能为力;

2. window.onerror

  • 输出参数错误星系、错误文件、行号、列号、错误对象
  • return true 防止异常向上抛出
  • 须写在执行代码最前面,否则有kennel捕获不到错误
  • 无法捕获语法错误、静态资源错误
  • 添加script的crossorigin属性并且设置静态资源Javascript的Response为Access-Control-Allow-Origin可以捕获的js静态资源错误

3.window.addEvenListener("error", function(e) {})

  • 可以捕获到资源脚本请求错误、无法判别http状态码
  • 不同浏览器下的error返回的对象不同需要兼容

4.Promise catch

  • 没有写catch的Promise抛出的错误无法被onerror和try-catch捕获到
  • 建议使用addEvenListener("unhandlerejection", function(e {}))可以捕获没有catch的Promise的异常

5.vue react 等框架错误
Vue.config.errorHandle = function(error, vm, info) {}
React: componentDidCatch = function(error, catch) {}

**6. 页面卡顿和崩溃 **
window.load和window.beforeunload

  window.addEventListener('load', function () {
      sessionStorage.setItem('good_exit', 'pending');
      setInterval(function () {
         sessionStorage.setItem('time_before_crash', new Date().toString());
      }, 1000);
   });

   window.addEventListener('beforeunload', function () {
      sessionStorage.setItem('good_exit', 'true');
   });

   if(sessionStorage.getItem('good_exit') &&
      sessionStorage.getItem('good_exit') !== 'true') {
      /*
         insert crash logging code here
     */
      alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash'));
   }
  1. 网页崩溃无法执行window.beforeunload

基于 Service Worker 的崩溃统计方案

p1:网页加载后,通过 postMessage API 每 5s 给 sw 发送一个心跳,表示自己的在线,sw 将在线的网页登记下来,更新登记时间;
p2:网页在 beforeunload 时,通过 postMessage API 告知自己已经正常关闭,sw 将登记的网页清除;
p3:如果网页在运行的过程中 crash 了,sw 中的 running 状态将不会被清除,更新时间停留在奔溃前的最后一次心跳;
sw:Service Worker 每 10s 查看一遍登记中的网页,发现登记时间已经超出了一定时间(比如 15s)即可判定该网页 crash 了。
心跳检测机制

// 页面 JavaScript 代码
if (navigator.serviceWorker.controller !== null) {
  let HEARTBEAT_INTERVAL = 5 * 1000; // 每五秒发一次心跳
  let sessionId = uuid();
  let heartbeat = function () {
    navigator.serviceWorker.controller.postMessage({
      type: 'heartbeat',
      id: sessionId,
      data: {} // 附加信息,如果页面 crash,上报的附加数据
    });
  }
  window.addEventListener("beforeunload", function() {
    navigator.serviceWorker.controller.postMessage({
      type: 'unload',
      id: sessionId
    });
  });
  setInterval(heartbeat, HEARTBEAT_INTERVAL);
  heartbeat();
}
const CHECK_CRASH_INTERVAL = 10 * 1000; // 每 10s 检查一次
const CRASH_THRESHOLD = 15 * 1000; // 15s 超过15s没有心跳则认为已经 crash
const pages = {}
let timer
function checkCrash() {
  const now = Date.now()
  for (var id in pages) {
    let page = pages[id]
    if ((now - page.t) > CRASH_THRESHOLD) {
      // 上报 crash
      delete pages[id]
    }
  }
  if (Object.keys(pages).length == 0) {
    clearInterval(timer)
    timer = null
  }
}

worker.addEventListener('message', (e) => {
  const data = e.data;
  if (data.type === 'heartbeat') {
    pages[data.id] = {
      t: Date.now()
    }
    if (!timer) {
      timer = setInterval(function () {
        checkCrash()
      }, CHECK_CRASH_INTERVAL)
    }
  } else if (data.type === 'unload') {
    delete pages[data.id]
  }
})

http请求异常和数据上报
htpp接口请求异常状态码上报、或者内部约定错误的上报形式
上报信息可能过多,可以采用随机选择、或者用户特征过滤的方式

总结:
可疑区域(try-catch)
全局js异常window.error
静态资源 addEvenListener("error", function(e){})
没有catch的Promise addEvenListener("unhandlerejection", function(e){})
网页崩溃:load和beforunload|+ workService监控
http请求
跨域脚本crossorigin和Response为Access-Control-Allow-Origin
框架单独处理
async await的异常处理方式:配合使用promise返回错误和得到数据的集合,根据是否有错误来抛出异常

你可能感兴趣的:(前端系统异常监控 - 基础)