前端捕获错误上报、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;
//资源加载错误不能捕获❎
 <img src="http://lx-zyy.com/image/errortest.png" alt="">
<script>
window.onerror = function (message, source, lineno, colno, error) {
            console.log("error", { message, source, lineno, colno, error });
        }
        </script>
        

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

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

//可以捕获资源加载错误✅
<img src="http://lx-zyy.com/image/errortest.png" alt="">
 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同步上报。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值