• 前端错误监控


    目录

    js运行时错误

    普通错误

    错误捕获

    捕获到的错误信息

    未捕获的Promise错误

    错误捕获方式

    更推荐的做法

    关于Vue 的 errorHandler

    关于 React 的 ErrorBoundary

    网络请求错误

    静态资源加载失败

    如何监控静态资源加载失败呢?

     Script error,拿不到错误信息?

    捕获AJAX 错误

    捕获 fetch 错误


    前端错误监控大分为两大类:js运行时错误,网络请求错误

    js运行时错误可分为:普通错误,未捕获的Promise错误

    网络请求错误可分为:静态资源加载失败,AJAX (XHR,fetch)请求失败

    js运行时错误

    普通错误

    比如我们调用了一个不存在函数

    错误捕获

    1. window.addEventListener('error', function (e) {
    2. console.log('error1:', e)
    3. // 上报
    4. // monitorSDK.report(你要上报的信息)
    5. })
    6. window.onerror = function (e) {
    7. console.log('error2:', e)
    8. }
    9. xxx();

    捕获到的错误信息

    未捕获的Promise错误

    可以看到,如果一个Promise发生错误,但是没有用catch进行处理,将会抛出一个错误,这种错误如何捕获呢?用第1种的方式可行吗?这里新增一个错误捕获方式

    1. window.addEventListener('error', function (e) {
    2. console.log('error1:', e)
    3. })
    4. window.onerror = function (e) {
    5. console.log('error2:', e)
    6. }
    7. window.addEventListener('unhandledrejection',function(e){
    8. console.log('unhandledreject:', e)
    9. })
    10. new Promise(()=>xxx);

    错误捕获方式

    可以看到,第1种并不能捕获Promise错误,而是需要用  window.addEventListener('unhandledrejection') 来捕获

    更推荐的做法

    为了使代码更加健壮,建议 catch 所有的Promise错误

    关于VueerrorHandler

    Vue为了防止应用崩溃,内部进行了 try catch ,导致没有错误抛出,我们可以通过在 errorHandler 里拿到错误信息,并主动上报

    关于 React 的 ErrorBoundary

    React 针对应用渲染时发生错误的处理方式和Vue不一样,如果渲染发生错误并且没有用ErrorBounbary包裹,整个应用将崩溃,React认为不显示比显示一个错误的UI更合理,当然了这个没有说绝对的谁好谁坏。
     

    1. class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
    2. static getDerivedStateFromError(e: any) {
    3. console.error('getDerivedStateFromError: ', e);
    4. // 这里可以做错误上报
    5. return { hasError: true };
    6. }
    7. constructor(props: ErrorBoundaryProps) {
    8. super(props);
    9. this.state = { hasError: false };
    10. }
    11. render() {
    12. if (this.state.hasError) {
    13. return '这是错误发生时的UI';
    14. }
    15. return this.props.children;
    16. }
    17. }
    18. export default ErrorBoundary;

    网络请求错误

    静态资源加载失败

    静态资源包括js,css,image,字体文件等

    如何监控静态资源加载失败呢?

    1. html>
    2. <html lang="en">
    3. <head>
    4. <script>
    5. window.addEventListener('error', function (e) {
    6. console.log('error1:', e)
    7. })
    8. script>
    9. head>
    10. <body>
    11. <img id="image" src="./404.png" alt="">
    12. <script>
    13. document.getElementsByTagName('img')[0]
    14. .addEventListener('error', function (e) {
    15. console.log('image error', e)
    16. })
    17. script>
    18. body>
    19. html>

    输入结果

    可以看到, window.addEventListener('error')并没有捕获到错误,这是为什么?
    原来静态资源的错误,并不会冒泡到window,只能在事件捕获阶段拿到,调整代码,第3个参数改为true

    1. window.addEventListener('error', function (e) {
    2. console.log('error1:', e)
    3. },true)

    成功拿到错误

     Script error,拿不到错误信息?

    Script error. 也被称为跨域错误,当网站请求并且执行一个非本域名下的脚本的时候,如果跨域脚本发生错误,就有可能抛出这个错误。由于项目中,我们的脚本都是放在 CDN 上的,因此这种错误最为常见。

    出于安全考虑,浏览器会刻意隐藏其他域的JS文件抛出的具体错误信息,这样做可以有效避免敏感信息无意中被不受控制的第三方脚本捕获。因此,浏览器只允许同域下的脚本捕获具体错误信息,而其他脚本只知道发生了一个错误,但无法获知错误的具体内容
    可以参考 Script error · Issue #3 · BetterJS/badjs-report · GitHub


    捕获AJAX 错误

    不论是XHR还是fetch,我们都是通过函数劫持的办法实现错误监控的

    XHR

    1. const trackXHR = () => {
    2. const XHR = window.XMLHttpRequest;
    3. const originSend = XHR.prototype.send;
    4. XHR.prototype.send = function () {
    5. const errorHandler = (event) => {
    6. try {
    7. if (event && event.currentTarget && event.currentTarget.status !== 200) {
    8. const log = {
    9. status: this.status,
    10. type: 'xhr',
    11. // 其他要上报的数据
    12. }
    13. // 这里上报
    14. console.log('log----', log)
    15. }
    16. } catch {
    17. // SDK error
    18. }
    19. }
    20. // 重写load、error、abort方法,来处理请求结束时的逻辑,但是为什么不用函数拦截呢?
    21. // 因为用户有时候可能不会去调用 xhr.onload、xhr.error、xhr.abort 方法,如果都没有调用,拦截函数也不会执行,
    22. // 所以这里可以用 addEventListener 的方式
    23. this.addEventListener('load', errorHandler, false)
    24. this.addEventListener('error', errorHandler, false)
    25. this.addEventListener('abort', errorHandler, false)
    26. return originSend.apply(this, arguments)
    27. }
    28. // 兼容一些特殊场景,有些场景 XHR 对象不存在responseURL属性,这里记录下来
    29. const originOpen = XHR.prototype.open
    30. XHR.prototype.open = function (methods, url, async) {
    31. this.ajaxURL = url;
    32. return originOpen.apply(this, arguments)
    33. }
    34. }

    捕获 fetch 错误

    1. const trackFetch = () => {
    2. if (!window.fetch) return;
    3. const originFetch = window.fetch;
    4. window.fetch = function () {
    5. return originFetch.apply(this, arguments)
    6. .then(res => {
    7. if (res.ok) {
    8. return res;
    9. }
    10. // 响应不为 ok 时,比如接口 400 404,500,上报错误信息
    11. }).catch(err=>{
    12. // 如果代码有bug,或者请求发生了跨域错误,则会执行这里
    13. // 在这里上报错误信息
    14. // 并且抛出错误,让错误能被其他地方捕获到
    15. throw err
    16. })
    17. }
    18. }

  • 相关阅读:
    4. MongoDB部署
    FPGA工程师面试试题集锦111~120
    【LeetCode】链表OJ题
    如何解决iQOO手机运行uniapp真机调试时无法识别的问题
    Java JVM生命周期、动态代理——Java JVM筑基
    js的toString方法
    2024 Web 新特性 - 使用 Popover API 创建弹窗
    Photoshop使用笔记总目录
    25个Matplotlib图的Python代码,复制直接可用
    C++面经
  • 原文地址:https://blog.csdn.net/illusion_melody/article/details/132790460