js基础 ---- 前端如何记录浏览器报错

一、浏览器常见的几种报错分类

  1、网络连接

  2、http劫持

  3、服务器错误

  4、前端代码错误

  5、前端兼容性问题

  6、用户操作错误

  7、跨域问题

二、如何记录这些问题

  一般在本地进行调试的时候 发生错误 我们一般习惯性的先看 console 查看日志是最简单的 但是当项目上线后 这种办法基本等于无效 

  1、如何收集错误信息

    (1)、虚拟机监控

      优点:是指标齐全,并且可以进行竞品监控

      缺点:是反映不全,容易失真

      (2)、脚本监控

      优点:是可以收集海量真实数据

      缺点:是影响性能,采样少的情况下容易失真

  2、常见的几种记录错误的方法

    (1)、访问浏览器时间记录 performance API

      在chrome浏览器控制台输入Performance.timing,会得到记录了一个浏览器访问各阶段的时间的对象。

      进行错误收集的时候,可以对比这些时间,看错误发生在什么阶段

      DNS 查询耗时 :domainLookupEnd - domainLookupStart

      TCP 链接耗时 :connectEnd - connectStart

      request 请求耗时 :responseEnd - responseStart

      解析 dom 树耗时 : domComplete - domInteractive

      白屏时间 :responseStart - navigationStart

      domready 时间 :domContentLoadedEventEnd - navigationStart

      onload 时间 :loadEventEnd – navigationStart

    (2)、脚本错误收集 window.onerror

      window.onerror可以捕捉运行时错误,可以拿到出错的信息,堆栈,出错的文件、行号、列号  

      要注意以下几点:

        要把window.onerror这个代码块分离出去,并且比其他脚本先执行(注意这个前提!)即可捕捉到语法错误。

        由于网络请求异常事件不会冒泡,需要在捕获阶段进行处理

        不能捕获promise的错误信息

        跨域资源需要专门处理,需要在script标签加上crossorigin属性,服务器设置Access-Control-Allow-Origin

        window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。

      解决方案:

          使用window.onerror和window.addEventListener('error')都能捕获,但是window.onerror含有详细的error堆栈信息,存在error.stack中,所以可以选择使用         onerror的方式对js运行时错误进行捕获。

          window.onerror = function (msg, url, lineNo, columnNo, error) {
            // 处理错误信息
          }
          // demo
          msg: Uncaught TypeError: Uncaught ReferenceError: a is not defined
          error.statck: TypeError: ReferenceError: a is not defined at http://xxxx.js:1:13
          window.addEventListener('error', event => (){
            // 处理错误信息
          }, false);
          // true代表在捕获阶段调用,false代表在冒泡阶段捕获。使用true或false都可以,默认为false

 

    (3)、promise的错误处理

        promise除了使用catch方法来捕获错误,还可以使用window的unhandledrejection事件捕获异常的

        window.addEventListener("unhandledrejection", function(e){
            // Event新增属性
            // @prop {Promise} promise - 状态为rejected的Promise实例
            // @prop {String|Object} reason - 异常信息或rejected的内容

            // 会阻止异常继续抛出,不让Uncaught(in promise) Error产生
            e.preventDefault()
        })
    (4)、try catch
        
无法捕捉到语法错误,只能捕捉运行时错误;
        可以拿到出错的信息,堆栈,出错的文件、行号、列号; 需要借助工具把所有的function块以及文件块加入try,catch,可以在这个阶段打入更多的静态信息。

           要注意的是try catch只能捕获同步代码的异常,对回调,setTimeout,promise等无能为力
          上报错误的方式

          后端提供接口,前端ajax上传  

          创建一个新的图片,url参数带上错误信息

            function report(error) {
               var reportUrl = 'http://xxxx/report';
               new Image().src = reportUrl + 'error=' + error;
            }
    (5)、fetch与xhr错误的捕获
        对于fetch和xhr,我们需要通过改写它们的原生方法,在触发错误时进行自动化的捕获和上报。
        改写fetch方法:
          function _errorFetchInit () {
            if(!window.fetch) return;
            
let _oldFetch = window.fetch;
            window.fetch = function () {
              return _oldFetch.apply(this, arguments)
              
.then(res => {
                      if (!res.ok) { // 当status不为2XX的时候,上报错误
                        }
                        return res;
                      }).catch(error => {
                          throw error;
                      })
                    }
                  }
          对于XMLHttpRequest的重写:

              // xhr的处理
              function _errorAjaxInit () {
              let protocol = window.location.protocol;
              if (protocol === 'file:') return;
                // 处理XMLHttpRequest
                if (!window.XMLHttpRequest) {
                  return;
                }
                let xmlhttp = window.XMLHttpRequest;
                // 保存原生send方法
                let _oldSend = xmlhttp.prototype.send;
                let _handleEvent = function (event) {
                  try {
                    if (event && event.currentTarget && event.currentTarget.status !== 200) {
                    // event.currentTarget 即为构建的xhr实例
                    // event.currentTarget.response
                    // event.currentTarget.responseURL || event.currentTarget.ajaxUrl
                    // event.currentTarget.status
                    // event.currentTarget.statusText
                   });
                  }
                  } catch (e) {va
                console.log('Tool\'s error: ' + e);
                 }
                }
                xmlhttp.prototype.send = function () {
                  this.addEventListener('error', _handleEvent); // 失败
                  this.addEventListener('load', _handleEvent); // 完成
                  this.addEventListener('abort', _handleEvent); // 取消
                  return _oldSend.apply(this, arguments);
                }
              }

         (6)、跨域错误

            当网站请求并执行一个托管在第三方域名下的脚本时,就可能遇到该错误。最常见的情形是使用 CDN 托管 JS 资源

            出于安全考虑,浏览器会刻意隐藏其他域的 JS 文件抛出的具体错误信息,这样做可以有效避免敏感信息无意中被不受控制的第三方脚本捕获。

            因此,浏览器只允许同域下的脚本捕获具体错误信息,而其他脚本只知道发生了一个错误,但无法获知错误的具体内容。

            解决:

              <script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

              此步骤的作用是告知浏览器以匿名方式获取目标脚本。这意味着请求脚本时不会向服务端发送潜在的用户身份信息(例如 Cookies、HTTP 证书等)。

              添加跨域 HTTP 响应头:

                Access-Control-Allow-Origin: * ||  Access-Control-Allow-Origin: http://test.com

三、Vue的错误捕捉
    vue内部发生的错误会被Vue拦截,因此vue提供方法给我们处理vue组件内部发生的错误。
      Vue.config.errorHandler = function (err, vm, info) {}
posted @ 2020-10-12 17:58  有梦想的咸鱼7  阅读(1214)  评论(0编辑  收藏  举报