前端错误监控

最近一直在做前端js错误监控的工作,在不断的打磨和完善中,发现里面还是知识点不少,现在就前端js错误监控做一些笔记和总结

为什么要做前端错误监控?

  1. 为了保证产品的质量

  2. 有些问题只存在于线上特定的环境

  3. 后端错误有监控,前端错误没有监控

下面会讲:

  • 前端错误的分类
  • 错误的捕获方式
  • 上报错误的基本原理

一. 前端错误的分类

  1. 即时运行错误:代码错误
  2. 资源加载错误:(js、css、图片加载失败)

二. 错误的捕获方式

  • 即时运行错误的捕获方式
    • try....catch
    • window.onerror
  • 资源加载错误的捕获方式
    • object.onerror
    • performance.getEntries
    • Error事件捕获

1.即时运行错误的捕获方式

1.try...catch

通过try...catch我们能够知道出错的信息,并且也有堆栈信息可以知道在哪个文件第几行第几列发生错误。

try {
           // 代码段
     } catch (err) {
          console.log(err.message)
     }

缺点:

  1. 没法捕捉try,catch块,当前代码块有语法错误,JS解释器压根都不会执行当前这个代码块,所以也就没办法被catch住;
  2. 没法捕捉到全局的错误事件,也即是只有try,catch的块里边运行出错才会被你捕捉到,这里的块你要理解成一个函数块

2.window.onerror

全局捕获。window.onerror会在页面发生js错误时被调用可以收集到错误字符串信息、发生错误的js文件,错误所在的行数、列数、和Error对象(里面会有调用堆栈信息等),还可以在window.onerror最后return true让浏览器不输出错误信息到控制台

/*
         * @param message{String}:错误消息
         * @param source{String}:引发错误的脚本的URL
         * @param lineno{Number}:发生错误的代码行
         * @param colno{Number}:发生错误的代码列
         * @param error{object}:错误对象
*/

        window.onerror = function (msg, url, line, colunm, error) {
            // 返回 true 则错误消息不显示在控制台,返回 false,则错误消息将会展示在控制台
            return true;
        }

3.object.onerror

img、script标签都可以添加onerror事件,当资源请求失败的时候,都会触发该事件。

var img = document.getElementById('img');
img.onerror=function(){
    console.log("出错啦");
}

4.performance.getEntries

performance是h5的新特性之一,使用该方法能获取到当前页面已经加载到的资源,返回的是一个数组对象。

例子获取页面中没有成功加载的图片资源?

let arr = [],
    imgList=null,
    num=0,
    reg = (/\.jpg$|\.jpeg$|.png$|\.gif$/i);

// 1.通过performance.getEntries()获取已经加载了的图片资源
performance.getEntries().forEach(item => {
    if (reg.test(item.name)) {
        arr.push(item.name)
    }
})
// 2.获取页面中所有的img标签
imgList=document.getElementsByTagName('img');
// 3.利用获取到的img的长度减去已经加载到的长度,如果大于0的部分,就是加载失败的
num=imgList.length-arr.length; 

控制台使用: var arr=[]; performance.getEntries().forEach((item,i)=>{console.log(arr[i]=item.name)}) 打印出网站中成功加载的所有资源。

通过 document.getElementsByTagName('img').length减去上面的成功加载就能得出报错的图片资源数量了。

// 返回网站内所有成功加载的png文件数量
var arr=[]; 
performance.getEntries().forEach((item,i)=>{console.log(arr[i]=item.name)})
arr.filter(function(item, index, arr){
    var search1 = arr[index];
    return search1.includes('.png',search1.length-4) != false;
}).length;

5. Error事件捕获

资源加载错误,虽然会阻止冒泡,但是不会阻止捕获。true:捕获,false:冒泡

// window.addEventListener第三个参数是true的时候是捕获的过程,false是冒泡的过程 
window.addEventListener('error',function(e){
        console.log("捕获",e)
    },true)

6.延伸

为了提升web性能,大部分web产品都有CDN部署,将资源部署到不同的域名上,但是我们都知道浏览器是有同源策略的,当加载不同域名的脚本发生错误时,语法错误的细节不会报告,仅返回"Script error"

既然跨域JS运行错误可以捕获,错误提示是什么,应该怎么处理?

捕获跨域错误

必须做俩件事:

  • 客户端:在请求资源的script标签中增加crossorigin属性
  • 服务端:设置 js资源响应头Access-Control-Origin:*
<script type="text/javascript" src="http://domain.com/a.js"  crossorigin></script>

三. 上报错误的方式

开发 Web 应用程序过程中的一种常见的做法,就是集中保存错误日志,以便查找重要错误的原因。那么我们怎么将js的错误信息记录到服务器数据库库中呢。

  • 采用Ajax通信的方式上报 (所有的错误监控都不是通过这种方式来做的;)
  • 利用Image对象上报(所有的监控体系都是这样做的,如谷歌)

1. 采用Ajax通信的方式上报

ajax来实现的弊端

  • 不支持跨域操作,因为很多情况下是一台服务器要负责处理多台服务器的错误;

  • 大多数Ajax通信都是通过javascript库提供的包装函数来处理,如果库代码本身就有问题, 而你还在依赖该库记录信息,可想而知,错误消息是不肯能得到记录的。

怎么办?我们可以使用Image对象巧妙的解决这个问题

2.利用Image对象上报

Image对象的优点:

  • 所有浏览器都支持 Image 对象,包括那些不支持XMLHttpRequest对象的浏览器。

  • 可以避免跨域限制。通常都是一台服务器要负责处理多台服务器的错误,而这种情况下使用 XMLHttpRequest 是不行的。

  • 在记录错误的过程中出问题的概率比较低。大多数 Ajax 通信都是由 JavaScript 库提供的包装函 数来处理的,如果库代码本身有问题,而你还在依赖该库记录错误,可想而知,错误消息是不 可能得到记录的。

/* 方法1 */
//利用这种方式发送一个请求非常简单,比Ajax简单,不需要借助任何第三方库;
(new Image()).src="http://baidu.com/test?r=error";
//一行代码实现一个资源向上报;/test?这个是上报路径;r=error加信息


/* 方法2 配合try...catch 更佳*/
function logError(sev, msg){
     var img = new Image(); 
     img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + encodeURIComponent(msg);
 } 

for (var i=0, len=mods.length; i < len; i++){
     try { 
            mods[i].init(); 
      } catch (ex){
            logError("nonfatal", "Module init failed: " + ex.message); 
      }
} 

参考文章1

参考文章2

参考文章3

posted @ 2020-02-29 20:56  给时光以生命  阅读(651)  评论(0编辑  收藏  举报