前端捕获错误上报、h5捕获错误上报

1、今天有幸被一个大哥问到了错误上报,之前没有做过,现在想想5年的前端生涯,竟然没弄过错误上报,可能没人信吧,哎,不说了进入正题,如是一个再牛逼的程序员,也不可能说没有写过bug,我们js在运行的过程中,不会导致引擎崩溃,最多导致当前出现bug的任务终止。然后逐级上报错误。类似冒泡事件。如果我们中间没有写错误处理的catch时,最后程序会到window对象结束。 首先我们先了解下web前端的错误类型有哪些? (1)JS执行错误 日常执行中主要有同步错误、语法错误、普通的异步任务错误、Promise任务错误、async五种异步任务错误。 (2)资源加载错误 资源加载错误主要有图片错误、font、css、scrit等资源的加载问题 (3)错误捕获 我们如果看过源码就知道,好多源码中都有try…catch 这个东西是怎么回事呢,他是捕获异常的,他只能对正常代码执行的错误进行捕获比如:

//可以捕获✅try{ console.log(person.name) }catch(error){console.log(“try catch error”,error)}//语法错误,不能捕获❎try{ const person.name}catch(error){console.log(“try catch error”,error)}//普通异步任务不能捕获❎try{ setTimeout(()=>{ console.log(person.name) })}catch(error){console.log(“try catch error”,error)}//promise不能捕获❎try{ new Promise((resolve)=>{ fun() resolve() })}catch(error){console.log(“try catch error”,error)}//async是有前提的捕获✅const getInfo = async ()=({ fun()})try { await getInfo() //必须配合await使用才能捕获}catch(error){ console.log(“try catch error”,error)}

资源加载标签肯定不能在代码块中执行,因为资源加载错误肯定没法捕获。 综上所述,我们总结下try…catch…的能力。 1、能捕获体内的同步执行的错误。 2、不能捕获语法错误; 3、不能捕获异步任务错误; 4、不能捕获promise异步错误; 5、不能捕获资源加载错误。

window.onerror 浏览器的window对象上自带了一个onerror方法

//正常执行的错误可以捕获✅,如下 window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); } console.log(person.name)

//语法错误,不能捕获❎window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); } const person.name

//普通异步任务错误,能捕获✅ window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); } setTimeout(() => { console.log(person.name) }, 1000);

//promise异步错误不能捕获❎window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); } new Promise((resolve) => { gio() resolve(“hello”) })

在这里插入图片描述

//async 任务错误不能捕获❎ window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); } const getInfo = async () => { gso() }; await getInfo; //资源加载错误不能捕获❎ window.onerror = function (message, source, lineno, colno, error) { console.log(“error”, { message, source, lineno, colno, error }); }

在这里插入图片描述 综上所述,window.onerror的捕获能力如下: 1、可以捕获所有同步任务的正常错误; 2、不能捕获语法错误; 3、可以捕获普通异步任务错误; 4、不能捕获promise异步任务错误; 5、不能捕获async的错误; 6、不能捕获资源加载错误。

window.addEventListener(‘error’) 我们从字面意思来看跟window.onerror差不多,实际应用中他们俩的用法还是有那么点区别的。 我先列举出不同的点,它可以监听资源加载的错误,除了不能监听new Image()资源加载的错误;

//可以捕获资源加载错误✅ window.addEventListener(“error”, (error) => { console.log(“error”, error) }, true)

在这里插入图片描述

//不能捕获new Image()❎ let imgSrc = new Image() imgSrc.src = “https://lx-zzy.com/image/node.png” window.addEventListener(“error”, (error) => { console.log(“error”, error) }, true)

在这里插入图片描述 跟window.onerror比较,它可以监听资源加载错误的捕获。

window.addEventListener(‘unhandledrejection’) 到目前位置我们的promise错误捕获问题我们还没得到解决,有些人会说,promise不是有catch么,但是现实中大多数同学不会每一个promise中单独写个catch,当然js中还有个方法捕获错误,他就是unhandledrejection,如下

window.addEventListener(“unhandledrejection”, (error) => { console.log(“error”, error) }, true) new Promise((resolve, reject) => { go() })

在这里插入图片描述 当然如果我们将没有catch的Promise放在async中去执行,unhandledrejection事件监听也能捕获到。所以async任务错误unhandledrejection事件监听也是可以支持捕获的。 经过以上问题我们测试得知: 在这里插入图片描述 由上图得知,四种捕获方式都不能捕获语法错误,那么我们可以想想,语法错误执行的时候我们就可以看到了,编译的时候是不是一般就可以发现了,因此我们不用捕获,我们从图中可以发现 addEventListener(“unhandledrejection”), addEventListener(“error”),几乎包括了所有的错误捕获,

window.addEventListener(“unhandledrejection”, (e) => { console.log(“error”, e) throw e.reason }) window.addEventListener(“error”, (errs) => { console.log(“error”, errs) return false; }, true) //把Promise及async任务中的错误捕获后用同步的逻辑抛出即可让onerror准确捕获到。 //这样我们就可以捕获web中大部分异常

接下来我们看下如何将捕获的错误进行上报。 ajax 我们最通用的上传方式当然是ajax,啊当然他有很大的弊端。 1、有严格的跨域限制,携带cookie的问题; 2、上报请求可能会阻塞业务。 3、请求容易丢失(被浏览器强制cancel)(可以使用ajax同步请求,但是这样会阻止页面加载以及关闭,影响用户体验,不支持这样做) Image 为了解决各种的问题,我们通过创建icon的方式进行上报,图片可以突破跨域限制,又能兼容所有的浏览器,而js和css等其他资源文件则可能出现安全拦截和跨域加载问题,但如果某些浏览器在实现上无法保证图片的载入,就会导致上报数据的丢失。

let imgSrc = new Image();imgSrc.width=1;imgSrc.height = 1;imgSrc.src = “http://www.xxx.com?data=xxx”

后来我又看到一个上报的方式SendBeacon 它解决了XMLHttpRequest和图片上报的绝大部分弊端:没有跨域问题、不阻塞业务,甚至能在页面unload阶段继续发送数据,完美地解决了普通请求在unload阶段被cancel导致丢数据的问题,唯一的问题就是IE并不支持 在这里插入图片描述 为了解决上述问题,便有了 navigator.sendBeacon 方法,使用该方法发送请求,可以保证数据有效送达,且不会阻塞页面的卸载或加载,并且编码比起上述方法更加简单。

navigator.sendBeacon(url, data);//url 就是上报地址,data 可以是 ArrayBufferView,Blob,DOMString 或 Formdata,根据官方规范,需要 request header 为 CORS-safelisted-request-header,在这里则需要保证 Content-Type 为以下三种之一://application/x-www-form-urlencoded//multipart/form-data//text/plain

我们一般会用到 DOMString , Blob 和 Formdata 这三种对象作为数据发送到后端,下面以这三种方式为例进行说明. DOMString 如果数据类型是 string,则可以直接上报,此时该请求会自动设置请求头的 Content-Type 为 text/plain。

const reportData = (url, data) => { navigator.sendBeacon(url, data);};

Blob 如果用 Blob 发送数据,这时需要我们手动设置 Blob 的 MIME type,一般设置为 application/x-www-form-urlencoded。

const reportData = (url, data) => { const blob = new Blob([JSON.stringify(data), { type: ‘application/x-www-form-urlencoded’, }]); navigator.sendBeacon(url, blob);};

Formdata 可以直接创建一个新的 Formdata,此时该请求会自动设置请求头的 Content-Type 为 multipart/form-data。

const reportData = (url, data) => { const formData = new FormData(); Object.keys(data).forEach((key) => { let value = data[key]; if (typeof value !== ‘string’) { // formData只能append string 或 Blob value = JSON.stringify(value); } formData.append(key, value); }); navigator.sendBeacon(url, formData);};//注意这种方式我们使用了JSON.stringify服务端需要parse才可以拿到

如果我们遇到浏览器不兼容,则可以使用降级处理 使用ajax同步上报。


比丘资源网 » 前端捕获错误上报、h5捕获错误上报

发表回复

提供最优质的资源集合

立即查看 了解详情