前端监控
一般一个完整的前端项目需要包含异常监控,我们需要在项目出现异常的时候第一时间通知到我们开发,然后及时修复bug。
现有方案
异常类型
从前端的角度来说,前端需要关注的异常一般包含一下两种:
原生js错误
常见的js原生错误,主要包含语法错误(SyntaxError)、引用错误(ReferenceError)、类型错误(TypeError)和范围错误(RangeError,经常出现在数组中,取下标)等等,这是前端代码不合格导致的,严重的情况就会出现页面白屏,比如在spa中渲染最主要的组件的时候出现了这些错误,则会导致白屏。对于线上出现这种异常那是致命的,所以我们非常需要有个监控来及时知道是否出现了语法错误。
接口异常
接口异常出现在某个接口出现非2xx的响应,如果我们的主要接口出现了网络错误,则会导致我们的页面加载不出来,这也是很严重的事故,所以我们也需要时刻关注这种异常。
资源加载异常
js、css和图片加载失败也是需要上报的,尤其是关键的资源,如果加载失败,则可能整个页面都是白屏
unhandledrejection
如果使用了promise但是没有处理promise,但是没有catch异常,则会导致unhandledrejection的异常,这个异常是无法被window.onerror或者window.addEventListener(‘error’)捕获到到,需要通过window.addEventListener(‘unhandlerejction’)来捕获
异常捕获
window.onerror
js提供了一个全局的捕获异常的方式,就是window.onerror
window.onerror = function(errorMessage, scriptURI, lineNumber, columnNumber, errorObj) {
}
可以看到它包含了异常的信息、出现异常的文件、出现异常的行列号以及异常对象(它包含堆栈信息),这些详细的信息是我们使用window.onerror的方式捕获异常的最主要原因,相对window.addEventListener无法做到这点。
但是它存在几个问题
1、基于安全考虑,无法捕获到跨域的异常。
2、不同浏览器异常信息支持不同,异常的堆栈不统一,甚至有些浏览器没有堆栈信息。 3、无法知道资源加载的异常。
第一个问题,可以设置crossorigin属性和js所在的域名设置CORS来解决。
第二个问题,我们可以利用TraceKit第三方npm包解决堆栈信息不统一的情况,而针对一些老浏览器没有堆栈信息的,就需要你手动对代码进行埋点,用try catch埋点所有的函数/方法了,有兴趣的可以看下我git上的一个做法。这里。这里特别说下,用try catch以后,代码容量会增加,但是性能影响微乎其微。淘宝的文章。 第三个问题,因为资源的加载错误不会冒泡,随意window.onerror无法捕获到,所以需要改为window.addEventListener的方式在捕获阶段捕获异常,但是你需要防止和window.onerror重复上报。
window.addEventListner
如上所述,我们是想利用window.addEventlistener来捕获资源加载出错的异常,但是又要避免和window.onerror的重复上报
window.addEventListener('error', event => (){
// 避免和window.onerror重复上报的js异常
const target = event.target || event.srcElement;
const isElementTarget = target instanceof HTMLScriptElement || target instanceof HTMLLinkElement || target instanceof HTMLImageElement;
if (!isElementTarget) return false;
// 上报资源地址
const url = target.src || target.href;
console.log(url);
}, true);
除此之外,window.addEventListener还可以用来捕获promise的异常
window.addEventListener('unhandlerejection', event => {
console.log(event.reason)
})
重新定义XMLHttpRequest、Jsonp、Fetch
对于接口的请求,我们可以通过重写请求的方法,包括了ajax的XMLHttpRequest和Jsonp,还有js自带的Fetch方法,上报响应status不是200的请求,或者其他的前端和后端定义好的某些响应为异常的请求,比如如果response的data返回的code不为0,也上报异常。
使用第三方方案
使用第三方成熟的库,比如sentry,这也是个人推荐的方式,因为上面的方式,一个是重复造轮子,一个是可能我们还有遗漏的异常没处理到。
使用第三方库最麻烦的地方是你们自己的公司是否已经搭建对应的平台,不过一般公司都会有这些异常上报平台,我这里基于sentry写了一个webpack的插件,用于自动化集成sentry的,大家可以参考一下点击这里。它主要做了两个工作:
1、初始化sentry。
2、如果webpack配置了sourcemap,则会自动上传sourcemap到sentry,并上传完后会删除sourcemap文件。