关于微信公众号:前端呼啦圈(Love-FED)我的博客:Raub的博客知乎专栏:前端呼啦圈前言大家好,又见面了,这次给大家分享前端异常监控中需要了解的异常捕获和上报机制的一些要点,也包括实用性的参考代码和流程。首先,为什么我们需要捕获并报告异常?俗话说,经过大量测试和联调的项目,有时会出现非常隐蔽的bug。只有通过完善的监控机制,才能有效减少这种复杂且不可预测的问题。因此,对于直接面向用户的前端来说,异常捕获和上报是至关重要的。虽然市面上已经有一些非常完备的前端监控系统,如sentry、bugsnag等,但只有知己知彼,方能百战不殆。只有理解了其中的原理和逻辑,才能使用得心应手。异常捕获方法1.trycatch通常,为了判断一段代码是否存在异常,我们会这样写:try{vara=1;varb=a+c;}catch(e){//捕获并处理控制台。日志(e);//ReferenceError:cisnotdefined}使用trycatch可以很好的捕获异常并进行相应的处理,以免导致页面挂掉,但是也有一些缺点,比如需要在代码中对异常进行Wrapping会导致页面臃肿,不适合整个项目的异常捕获。2、与trycatch相比,window.onerror提供了全局监听异常的功能://异常信息console.log('scriptURI:'+scriptURI);//异常文件路径console.log('lineNo:'+lineNo);//异常行号console.log('columnNo:'+columnNo);//异常列号console.log('error:'+error);//异常堆栈信息};控制台日志(一);如图:window.onerror不仅提供了我们的错误信息,还提供了error可以准确定位行号和列号,看起来正是我们想要的,但是接下来就是填坑的过程了.异常捕获问题1.脚本错误。我们合理地尝试在本地页面上捕获异常,例如:这里为了优化加载我们把静态资源放在外域,但是抓取了异常信息为:经过分析,发现window.onerror无法捕获跨域后的异常信息,所以返回Scripterror。解决方法是配置脚本属性crossorigin="anonymous",在server-Origin中加入Access-Control-Allow。一般CDN网站会将Access-Control-Allow-Origin配置为*,即所有域名都可以访问过。2、sourceMap解决跨域或同域保存脚本后,可将代码压缩后发布。这时候就会出现压缩后的代码找不到原来的错误位置的问题。如图,我们使用webpack将代码打包压缩到bundle.js中://webpack.config.jsvarpath=require('path');//webpack4.1.1module.exports={mode:'development',entry:'./client/index.js',output:{filename:'bundle.js',path:path.resolve(__dirname,'client')}}最后我们页面引入的脚本文件是这样的this:!function(e){varo={};functionn(r){if(o[r])returno[r].exports;vart=o[r]={i:r,l:!1,出口:{}}...;所以我们看到的异常信息是这样的:lineNo可能是一个很小的数字,一般是1,而columnNo会是一个很大的数字,这里是730,因为所有的代码都被压缩到一行了。那么如何解决呢?聪明的童鞋可能已经猜到source-map开启了。是的,我们使用webpack打包压缩生成脚本对应的地图文件进行跟踪。在webpack中开启source-map功能:module.exports={...devtool:'#source-map',...}在打包压缩文件的最后会有这样的注释:!function(e){varo={};functionn(r){if(o[r])返回o[r].exports;vart=o[r]={i:r,l:!1,exports:{}}...;//#sourceMappingURL=bundle.js.map表示这个文件对应的map文件是bundle.js.map。下面是一个source-map文件的内容,是一个JSON对象:version:3,//Sourcemapversionsources:["webpack:///webpack/bootstrap",...],//转换前Filenames:["installedModules","__webpack_require__",...],//转换前的所有变量名和属性名mappings:"aACA,IAAAA,KAGA,SAAAC...",//记录位置信息文件的字符串:"bundle.js",//转换后的文件名sourcesContent:["//模块缓存varinstalledModules={};..."],//源代码sourceRoot:""//转换前的文件如果你想想了解更多sourceMap,可以去:JavaScriptSourceMap详细解释是这样的。既然我们已经获取到了脚本对应的map文件,那么如何分析获取文件压缩前的异常信息呢?下面报异常的时候再介绍这个。3.MVVM框架现在越来越多的项目开始使用前端框架。在MVVM框架中,如果要使用window。您的异常信息由框架自身的异常机制捕获。例如,在Vue2.x中,我们应该像这样捕获全局异常:Vue.config.errorHandler=function(err,vm,info){let{message,//异常信息名,//异常名script,//异常脚本urlline,//异常行号列,//异常列号stack//异常堆栈信息}=err;//vm是抛出异常的Vue实例//info是Vue特有的错误信息,比如错误所在的生命周期钩子在栈中可以找到信息,可以通过正则匹配得到,然后上报。同样,react也提供了异常处理的方法。React16.x版本引入了错误边界:classErrorBoundaryextendsReact.Component{constructor(props){super(props);this.state={hasError:false};}componentDidCatch(error,info){this.setState({hasError:true});//向服务器报告异常信息logErrorToMyService(error,info);}render(){if(this.state.hasError){返回“错误”;}返回this.props.children;}}那么我们可以这样使用这个组件:
