zoukankan      html  css  js  c++  java
  • web前端监控的三个方面探讨

    一. js错误监控方式

    1. 主动判断

    我们在一些运算之后,得到一个期望的结果,然而结果不是我们想要的

    // test.js
    function calc(){
      // code...
      return val;
    }
    if(calc() !== "someVal"){
      Reporter.send({
        position: "test.js::<Function>calc"
        msg: "calc error"
      });
    }

    这种属于逻辑错误/状态错误的反馈,在接口 status 判断中用的比较多。

    2. try..catch 捕获

    判断一个代码段中存在的错误:

    try {
      init();
      // code...
    } catch(e){
      Reporter.send(format(e));
    }

    以 init 为程序的入口,代码中所有同步执行出现的错误都会被捕获,这种方式也可以很好的避免程序刚跑起来就挂。

    3. window.onerror

    捕获全局错误:

    window.onerror = function() {
      var errInfo = format(arguments);
      Reporter.send(errInfo);
      return true;
    };

    在上面的函数中返回 return true,错误便不会暴露到控制台中。下面是它的参数信息:

    /**
     * @param {String}  errorMessage   错误信息
     * @param {String}  scriptURI      出错的文件
     * @param {Long}    lineNumber     出错代码的行号
     * @param {Long}    columnNumber   出错代码的列号
     * @param {Object}  errorObj       错误的详细信息,Anything
     */
    window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) { 
        // code..
    }

    window.onerror 算是一种特别暴力的容错手段,try..catch 也是如此,他们底层的实现就是利用 C/C++ 中的 goto 语句实现,一旦发现错误,不管目前的堆栈有多深,不管代码运行到了何处,直接跑到顶层或者 try..catch 捕获的那一层,这种一脚踢开错误的处理方式并不是很好。

    关于 window.onerror 还有两点需要值得注意

    1. 对于 onerror 这种全局捕获,最好写在所有 JS 脚本的前面,因为你无法保证你写的代码是否出错,如果写在后面,一旦发生错误的话是不会被 onerror 捕获到的。
    2. 另外 onerror 是无法捕获到网络异常的错误。

    当我们遇到 <img src="./404.png"> 报 404 网络请求异常的时候,onerror 是无法帮助我们捕获到异常的。

    <script>
      window.onerror = function (msg, url, row, col, error) {
        console.log('我知道异步错误了');
        console.log({
          msg,  url,  row, col, error
        })
        return true;
      };
    </script>
    <img src="./404.png">

    由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断 HTTP 的状态是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。

    <script>
    window.addEventListener('error', (msg, url, row, col, error) => {
      console.log('我知道 404 错误了');
      console.log(
        msg, url, row, col, error
      );
      return true;
    }, true);
    </script>
    <img src="./404.png" alt="">

    这点知识还是需要知道,要不然用户访问网站,图片 CDN 无法服务,图片加载不出来而开发人员没有察觉就尴尬了。

    Promise 错误

    通过 Promise 可以帮助我们解决异步回调地狱的问题,但是一旦 Promise 实例抛出异常而你没有用 catch 去捕获的话,onerror 或 try-catch 也无能为力,无法捕捉到错误。

    window.addEventListener('error', (msg, url, row, col, error) => {
      console.log('我感知不到 promise 错误');
      console.log(
        msg, url, row, col, error
      );
    }, true);
    Promise.reject('promise error');
    new Promise((resolve, reject) => {
      reject('promise error');
    });
    new Promise((resolve) => {
      resolve();
    }).then(() => {
      throw 'promise error'
    });

    虽然在写 Promise 实例的时候养成最后写上 catch 函数是个好习惯,但是代码写多了就容易糊涂,忘记写 catch。

    所以如果你的应用用到很多的 Promise 实例的话,特别是你在一些基于 promise 的异步库比如 axios 等一定要小心,因为你不知道什么时候这些异步请求会抛出异常而你并没有处理它,所以你最好添加一个 Promise 全局异常捕获事件 unhandledrejection。

    window.addEventListener("unhandledrejection", function(e){
      e.preventDefault()
      console.log('我知道 promise 的错误了');
      console.log(e.reason);
      return true;
    });
    Promise.reject('promise error');
    new Promise((resolve, reject) => {
      reject('promise error');
    });
    new Promise((resolve) => {
      resolve();
    }).then(() => {
      throw 'promise error'
    });

    window.onerror 能否捕获 iframe 的错误

    当你的页面有使用 iframe 的时候,你需要对你引入的 iframe 做异常监控的处理,否则一旦你引入的 iframe 页面出现了问题,你的主站显示不出来,而你却浑然不知。

    首先需要强调,父窗口直接使用 window.onerror 是无法直接捕获,如果你想要捕获 iframe 的异常的话,有分好几种情况。

    如果你的 iframe 页面和你的主站是同域名的话,直接给 iframe 添加 onerror 事件即可。

    <iframe src="./iframe.html" frameborder="0"></iframe>
    <script>
      window.frames[0].onerror = function (msg, url, row, col, error) {
        console.log('我知道 iframe 的错误了,也知道错误信息');
        console.log({
          msg,  url,  row, col, error
        })
        return true;
      };
    </script>

    读者可以通过 npm run iframe 查看效果:

    如果你嵌入的 iframe 页面和你的主站不是同个域名的,但是 iframe 内容不属于第三方,是你可以控制的,那么可以通过与 iframe 通信的方式将异常信息抛给主站接收。与 iframe 通信的方式有很多,常用的如:postMessage,hash 或者 name 字段跨域等等,这里就不展开了,感兴趣的话可以看:跨域,你需要知道的全在这里

    如果是非同域且网站不受自己控制的话,除了通过控制台看到详细的错误信息外,没办法捕获,这是出于安全性的考虑,你引入了一个百度首页,人家页面报出的错误凭啥让你去监控呢,这会引出很多安全性的问题。

    异常上报方式

    监控拿到报错信息之后,接下来就需要将捕捉到的错误信息发送到信息收集平台上,常用的发送形式主要有两种:

    1. 通过 Ajax 发送数据
    2. 动态创建 img 标签的形式

    实例 - 动态创建 img 标签进行上报

    function report(error) {
      var reportUrl = 'http://xxxx/report';
      new Image().src = reportUrl + 'error=' + error;
    }


    收集异常信息量太多,怎么办

    如果你的网站访问量很大,假如网页的 PV 有 1kw,那么一个必然的错误发送的信息就有 1kw 条,我们可以给网站设置一个采集率:

    Reporter.send = function(data) {
      // 只采集 30%
      if(Math.random() < 0.3) {
        send(data)      // 上报错误信息
      }
    }
     

     

     

    二. 接口请求时长

        /**
         * 拦截接口请求,上报接口信息
         */
        //统一拦截ajax请求
        var start_time = 0,
            gap_time = 0;  //计算请求延时
        window.addEventListener('ajaxReadyStateChange', function (e) {
            var xhr = e.detail,
                status = xhr.status,
                readyState = xhr.readyState,
                responseText = xhr.responseText;
    
            /**
             * 计算请求延时
             */ 
            if(readyState == 1){
                start_time = (new Date()).getTime();
            }
            if(readyState == 4){
                gap_time = (new Date()).getTime() - start_time;
            }
            /**
             * 上报请求信息
             * @Author   smy
             * @DateTime 2018-06-27T16:32:30+0800
             */
            if(readyState == 4){
                httpReport(gap_time, status, xhr.responseURL)
            }
    
        })

    三. 页面加载时长

    参见:https://blog.oldj.net/2012/01/09/measuring-the-user-latency/

    --------------------------------------------------------------

    已知问题:

      1. ios苹果不支持crossorigin=“anonymous”, 只支持crossorigin="use-credentials",cdn 不支持credentials。

      2. ios 会对客户端调用webview方法找不到进行报错到window.onerror, 当上报的值是不存在的对象属性时,报错内容为global code,比如这时上报error.stack, 此时error为null,应上报message。

    ---------------------------------------------------------------

    参考:

    https://www.cnblogs.com/hustskyking/p/fe-monitor.html

    http://web.jobbole.com/93684/

    https://github.com/happylindz/blog/issues/5

  • 相关阅读:
    leetcode 92. 反转链表 II
    leetcode记录1 快速排序
    Jmeter入门总结
    Jmeter 元件作用域、集合点、检查点
    Jmeter 实例
    badboy脚本开发
    Jmeter 常用功能介绍
    简单的自创线程池
    多线程
    IO多路复用
  • 原文地址:https://www.cnblogs.com/saysmy/p/9355298.html
Copyright © 2011-2022 走看看