• 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

  • 相关阅读:
    AUDIT审计的一些使用
    HOW TO PERFORM BLOCK MEDIA RECOVERY (BMR) WHEN BACKUPS ARE NOT TAKEN BY RMAN. (Doc ID 342972.1)
    使用BBED理解和修改Oracle数据块
    Using Class of Secure Transport (COST) to Restrict Instance Registration in Oracle RAC [ID 1340831.1]
    调试利器GDB概念
    第4章 思科IOS
    第3章 ip地址和子网划分
    第2章 TCPIP
    2020年阅读过的黑客资源推荐篇
    第1章 计算机网络
  • 原文地址:https://www.cnblogs.com/saysmy/p/9355298.html
Copyright © 2020-2023  润新知