Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 575|回复: 0

前端异常采集

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-8-27 12:39:06 | 显示全部楼层 |阅读模式

    为什么要做前端代码异常采集?好问题!
    为了用户能安心用产品,不至于时不时“卡壳”崩溃。
    为了能高效定位线上代码的异常并提供简单提示信息。
    为了程序猿同胞们能睡个好觉。

    本文完整示例请移步github:FEerrorLog

    捕获异常的方法

    js捕获异常的方法,两三个而已。

    1. try...catch 优缺点已有很多论述和解决方案,本文的异常采集并未建立在该方法之上,只是少量使用。
    2. window.onerror和方法3类似但不如方法3强大,因此未选用此方法。
    3. window.addEventListener('error',function(){},true),采用此方法。

    前端异常包含两部分:
    第一部分:window.onerror()能捕获到的异常,当然如果用addEventListener无论冒泡还是捕获阶段也能捕获到该异常。
    第二部分:资源加载失败,即<img><script>标签上的onerror,这个异常无法通过冒泡到达window,但是可以在捕获阶段拿到,这就是为什么要将addEventListener第三个参数置成true了。

    注意:为保证该异常采集脚本能执行到,不被先行执行的脚本里面的报错阻断,该脚本要放到最前面。

    可能的异常及采集方案

    1. 资源加载失败,样式、图片、脚本文件的请求异常,比如js加载404了
    2. js脚本异常,即控制台常见的Error信息
    3. 检测HTML劫持,比如被运营商强行注入标签或脚本
    4. 页面样式丢失,CSS 展现异常

    1. 资源加载失败

    http异常用js几乎抓不到有用异常信息,但是404异常可以进行简单处理,此时是不会执行onerror的回调函数的。因为在addEventListener捕获到的异常信息中你可以发现,对应于onerror的五个回调参数根本不存在了,但是addEventListener中除这五个外,还有其他可以用的key,如果想获取加载失败的资源是哪个,可以去target中找些有用信息,我使用的是e.target.outerHTML

    "HttpError at " + (e.target.baseURI || location.href) + " outerHTML:" + e.target.outerHTML
    

    2. js异常

    一般需要采集的信息:

    1. 异常的提示信息,会直接告诉你是什么异常。这是识别一个异常的最重要依据,即e.message中的信息。
    2. JS 文件名:异常发生在那个文件中。是堆栈信息中最顶层的那个文件。即e.filename。
    3. 异常所在行、列:异常的具体位置。行信息各浏览器基本还是一致的,列信息的差别较大,仅供参考。
    4. 堆栈信息:异常信息发生的堆栈,也是函数调用的堆栈信息,每下一层都是上一层的运行环境。即e.error.stack。每一层都包含类型、文件、行、列信息。但是注意堆栈信息可能会比较多,可以根据需要截取上报。safari和firfox的e.error.stack中不包含以上1,2,3的信息,只有堆栈信息,而chrome和IE中都包含,此处需要做兼容处理。
    5. 发生异常的设备信息,可以从window.navigator中选取自己需要的信息,或者直接使用window.navigator.userAgent
    6. 发生异常的时间点,不多说。

    js主动抛出异常
    js异常除了可以是系统抛出的几类异常,还可以是开发者利用throw关键字主动抛出异常。
    值:可以是字符串、数字逻辑值或对象
    使用方式:

    //利用Error对象或其实例,采集到的异常系统自动为其添加了堆栈信息,和系统抛出异常基本类似
    throw new Error('Problem description.')
    throw Error('Problem description.') 
    //直接利用关键字抛出内容,会完全复写event.error的内容,不推荐使用。
    throw 'Problem description.' 
    throw null 
    

    另外:
    console.error()和throw new Error()抛出的错误信息是有本质区别的。前者不会阻断js运行,也不会被error事件捕捉到,只是在控制台打印错误信息。

    以下方式可以阻止异常信息在控制台中显示,线上可以自行收集异常信息后阻止外人看到控制台报错,开发环境不建议使用。

        window.addEventListener('error', (function(e) {
            console.log("-----errorEvent----", e)
            e.preventDefault()  //这里换成 return false或return true均不行!
        }), true);
        
        window.onerror = function(msg, url, line, col, error) {
            console.log("------errorInfo---",msg, url, line, col, error)
            return true;   //这里用return false不行!
        }
    

    3. 检测html劫持

    我选用的方案是保存真实环境中的html信息,并对比原html,检测是否有被篡改。
    采集html文档用到的是document.documentElement.outerHTML。但是有一点需要注意,上面已提到,该文件需要放在最前面,所以直接用该方法拿到的可能只有<head>中的html。因此如果想拿到完整的页面信息,需要将采集时间点放到onload以后。

        //所有io操作最好都try...catch一下,这里是防止储存的信息超过localStorage的最大限制。关于最大限制是多少已经有不少人说过了,大家可以选择性看一些,如果有必要可以亲测一下。
        window.addEventListener("load", function() {
            try {
                localStorage.setItem("hawkeyeHtml", document.documentElement.outerHTML);
            } catch (e) {
                //超过限度时,chrome和safari的e.name为'QuotaExceededError',FF的e.name为'NS_ERROR_DOM_QUOTA_REACHED'
                console.error(e)
            }
        })
    

    4. 页面样式丢失

    尚未做此数据采集和监控,目前考虑大体思路和html劫持类似,保存截屏图片,用一定算法和正常样式下做对比,超过一定差异值即判定为样式异常。

    数据处理方式:

    1. 上报监控服务器:便于统一监控异常数量类型等
      方案:我司仍选择img的属性src进行上报,一是考虑到解析性能,二是考虑到要为多站点服务,方便跨域上报。
    2. html页面打印前端异常:便于快速准确定位某使用环境崩溃原因
      方案:采集到信息储存在localstorage中,注意控制储存的条数。在需要查看异常信息的网站中增加该页面,取出进行简单处理即可。

    缺陷处理

    1. 线上代码是混淆压缩的,无行号
      解决方案:线上也用sourceMap来解决,至于sourMap是什么,怎么使用,根据项目不同,可自行google。
    2. 跨域的js,异常信息只有一个"Script error"。虽然js拿不到任何其他异常信息,但是控制台能打印出全部异常信息。所以
      解决方案一:匹配到"Script error",引导开者去控制台查看或直接过滤掉。
      解决方案二:解决跨域问题,分两步。一:静态资源请求需要加多一个Access-Control-Allow-Origin头部。二:<scrip>标签加上crossorigin属性
    3. 跨域的js,获取不到js文件名,会拿到at <anonymous>:1:1酱紫的信息,暂时没找到解决方案

    推荐文章:JavaScript Errors Handbook:里面有部分内容已不适用,具体实施请注意验证

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 12:00 , Processed in 0.054465 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表