JS前端错误监控捕获以及上报方法详解

前端错误捕获方法

前端捕获错误的方法:

try..catch:捕获的异常必须是线程执行进入到try...catch且try...catch未执行完的时候抛出来。

语法异常在语法检查阶段就报错了,线程尚未进入try...catch代码块,所以无法捕获到异常。

try {
    a.
}catch(e) {
    console.log('catch error:', e)
}

不能捕获setTimeout或者Promise中的错误。以下错误都不能捕获。如果想捕获,要将try...catch放入到异步代码内部。

        try {
            new Promise((res, rej) => {
                rej('promise reject error')
                // throw new Error('promise throw error')
            })
        } catch (e) {
            console.log('catch error:', e)
        }
​
​
        try {
            setTimeout(() => {
                throw new Error('setTimeout throw error')
            }, 0)
        } catch (e) {
            console.log('catch error:', e)
        }

能捕获async 异常

        async function fn() {
            try {
                let res = await new Promise((res, rej) => {
                    // rej('my reject err') // unhandledrejection 可以处理
                    throw Error('my throw error') // unhandledrejection 可以处理
                })
            } catch (err) {
                console.log('catch err', err)
            }
        }
​
        fn()

window.onerror:当资源加载失败或无法使用时,会在Window对象触发error事件,无法捕获promise错误,可以捕获setTimeout错误。

当加载自不同域的脚本中发生语法错误时,浏览器为避免信息泄露的安全风险,语法错误的细节将不会报告给浏览器console中,而是使用"Script error."信息代替。解决办法是为 script 标签添加 crossOrigin 属性,并且服务端配置Access-Control-Alow-Origin:*

unhandledrejection:当 Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件

不同场景错误处理方式

总结先行: addEventListener('error') + addEventListener('unhandledrejection') 的方式恰好能够覆盖5种异常错误(同步任务,普通异步任务,promise任务,async任务,资源加载)的捕获。

可以将unhandledrejection捕获到的错误throw出来让error进行捕获之后统一上报。

  • 跨域资源加载问题:window.addEventListener('error',()=>{}),并且script 标签添加 crossOrigin 属性,并且服务端配置Access-Control-Alow-Origin
  • 定时器内部函数抛出错误:window.onerror或者window.addEventListener('error',()=>{})
  • 静态资源加载的异常:window.addEventListener('error')可以捕获,但是window.onerror不能捕获
  • 网络请求的异常:axios的响应拦截器
  • 线上压缩代码:开启sourceMap

promise:常常配置catchhandler进行处理,没有处理的rejected的promise通过unhandledrejection

// 能触发 unhandledrejection ,因为未显式处理reason 
Promise.reject('error').then() 
Promise.reject('error').then(console.log) 
​
// 不能触发 unhandledrejection ,因为已处理reason 
Promise.reject('error').then(console.log, console.log) 
// 不能触发 unhandledrejection ,因为没处理reason,直接抛出异常 
Promise.reject('error')

React捕获错误:错误边界(Error Boundaries)

部分 UI 的 JavaScript 错误不应该导致整个应用崩溃,错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。错误边界可以捕获发生在整个子组件树的渲染期间、生命周期方法以及构造函数中的错误。

错误边界无法捕获以下场景中产生的错误:

  • 事件处理(了解更多)
  • 异步代码(例如 setTimeoutrequestAnimationFrame 回调函数)
  • 服务端渲染
  • 它自身抛出来的错误(并非它的子组件)

Vue捕获错误:

全局-Vue.config.errorHandler:指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。

  • 从 2.2.0 起,这个钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃。
  • 从 2.4.0 起,这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了。
  • 从 2.6.0 起,这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理。
  • 错误追踪服务 Sentry 和 Bugsnag 都通过此选项提供了官方支持。

生命周期钩子-errorCaptured:在捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传

传播规则:

  • 默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。
  • 如果一个组件的 inheritance chain (继承链)或 parent chain (父链)中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
  • 如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler
  • 一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler

错误信息上报

捕获到错误信息后进行上报,对于前端监控很重要。

上报的方式有三种:

ajax进行上报

发现错误的时候上传错误到接口进行存储。

但是存在一些问题:

  • 有严格的跨域限制
  • 上报请求可能会阻塞业务
  • 请求容易丢失(被浏览器强制cancel)

image上报

由于图片天然可跨域,又能兼容所有的浏览器,而js和css等其他资源文件则可能出现安全拦截和跨域加载问题。

let img = new Image()
img.src='请求的url'

但由于是一个get请求,上报的数据量在不同的浏览器下上限不一致(2kb-8kb),这就可能出现超出长度限制而无法上报完整数据的情况。因此,图片上报也是一个“不安全”的方式。

sendBeacon

sendBeacon

navigator.sendBeacon() 方法可用于通过 HTTP POST 将少量数据 异步 传输到 Web 服务器。

它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术

这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向 Web 服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 unload 事件处理器中产生的异步 XMLHttpRequest。

navigator.sendBeacon(url, data);

使用 sendBeacon() 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:

  • 数据发送是可靠的。
  • 数据异步传输。
  • 不影响下一导航的载入。

以上就是JS前端错误监控捕获以及上报方法详解的详细内容,更多关于JS前端错误监控捕获上报的资料请关注脚本之家其它相关文章!

你可能感兴趣的:(JS前端错误监控捕获以及上报方法详解)