前端异常监控-看这篇就够了

2018-11-09 admin

如果debug是移除bug的流程,那么编程就一定是将bug放进去的流程。 如果没有用户反馈问题,那就代表我们的产品棒棒哒,对不对?

主要内容

  • Web规范中相关前端异常
  • 异常按照捕获方式分类
  • 异常的捕获方式
  • 日志上报的方式

前端异常类型(Execption)

  • ECMAScript exceptions <==> IDL 的简单异常

    当脚本代码运行时发生的错误,会创建Error对象,并将其抛出,除了通用的Error构造函数外,以下是另外几个ECMAScript 2015中定义的错误构造函数。

    • EvalError eval错误
    • RangeError 范围错误
    • ReferenceError 引用错误
    • TypeError 类型错误
    • URIError URI错误
    • SyntaxError 语法错误 (这个错误WebIDL中故意省略,保留给ES解析器使用)
    • Error 通用错误 (这个错误WebIDL中故意省略,保留给开发者使用使用)
  • DOMException 最新的DOM规范定义的错误类型集,兼容旧浏览的DOMError接口, 完善和规范化DOM错误类型。

    • IndexSizeError 索引不在允许的范围内
    • HierarchyRequestError 节点树层次结构是不正确的。
    • WrongDocumentError 对象是错误的
    • InvalidCharacterError 字符串包含无效字符。
    • NoModificationAllowedError 对象不能被修改。
    • NotFoundError 对象不能在这里被找到。
    • NotSupportedError 不支持的操作
    • InvalidStateError 对象是一个无效的状态。
    • SyntaxError 字符串不匹配预期的模式
    • InvalidModificationError 对象不能以这种方式被修改
    • NamespaceError 操作在XML命名空间内是不被允许的
    • InvalidAccessError 对象不支持这种操作或参数。
    • TypeMismatchError 对象的类型不匹配预期的类型。
    • SecurityError 此操作是不安全的。
    • NetworkError 发生网络错误
    • AbortError 操作被中止
    • URLMismatchError 给定的URL不匹配另一个URL。
    • QuotaExceededError 已经超过给定配额。
    • TimeoutError 操作超时。
    • InvalidNodeTypeError 这个操作的 节点或节点祖先 是不正确的
    • DataCloneError 对象不能克隆。

前端错误异常按照捕获方式分类

  • [x] 运行时异常

  • [x] 资源加载异常

    • img
    • script
    • link
    • audio
    • video
    • iframe
    • …外链资源的DOM元素
  • [x] 异步请求异常

  • [x] Promise异常

  • [ ] CSS中资源异常

    • @font-face
    • background-image
    • …暂时无法捕获

前端错误异常的捕获方式

  • try-catch (ES提供基本的错误捕获语法)

    • 只能捕获同步代码的异常
    • 回调
    • setTimeout
    • promise
  • window.onerror = cb (DOM0)

  • window.addEventListener(‘error’, cb, true) (DOM2)

  • window.addEventListener(“unhandledrejection”, cb) (DOM4)

  • Promise.then().catch(cb)

  • 封装XMLHttpRequest&fetch | 覆写请求接口对象

try-catch-finally

将能引发异常的代码块放到try中,并对应一个响应,然后有异常会被捕获

  try {
    // 模拟一段可能有错误的代码
    throw new Error("会有错误的代码块")
  } catch(e){
    // 捕获到try中代码块的错误得到一个错误对象e,进行处理分析
    report(e)
  } finally {
    console.log("finally")
  }

onerror事件

window.onerror

当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的事件,并执行window.onerror()

/**
 * @description 运行时错误处理器
 * @param {string} message 错误信息
 * @param {string} source 发生错误的脚本URL
 * @param {number} lineno 发生错误的行号
 * @param {number} colno 发生错误的列号
 * @param {object} error Error对象
 */
function err(message,source,lineno,colno,error) {...}
window.onerror = err

element.onerror

当一项资源(如<img><script>)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。

element.onerror = function(event) { ... } //注意和window.onerror的参数不同

注意:这些error事件不会向上冒泡到window,不过能被单一的window.addEventListener捕获。

window.addEventListener

addEventListener相关的一些内容

W3C DOM2 Events规范中提供的注册事件监听器的方法, 在这之前均使用 el.onclick的形式(DOM0 规范的基本内容,几乎所有浏览器都支持)。

注意: 接口的几种语法

error事件捕获资源加载错误

资源加载失败,不会冒泡,但是会被addEventListener捕获,所以我们可以指定在加载失败事件的捕获阶段捕获该错误。

注意: 接口同时也能捕获运行时错误。

window.addEventListener("error", function(e) {
    var eventType = [].toString.call(e, e);
    if (eventType === "[object Event]") { // 过滤掉运行时错误
      // 上报加载错误
      report(e)
    }
  },
  true
);

unhandledrejection事件捕获Promise异常

最新的规范中定义了 unhandledrejection事件用于全局捕获promise对象没有rejection处理器时异常情况。

window.addEventListener("unhandledrejection", function (event) {
    // ...your code here to handle the unhandled rejection...

    // Prevent the default handling (error in console)
    event.preventDefault();
});

Promise.then().catch(cb).finally()

Promise中的错误会被Promise.prototype.catch捕获,所以我们通过这种方式捕获错误,这包括一些不支持unhandledrejection事件的环境中promisede polyfill实现。

new Promise(function(resolve, reject) {
  throw 'Uncaught Exception!';
}).catch(function(e) {
  console.log(e); // Uncaught Exception!
});

封装XMLHttpRequest&fetch | 覆写请求接口对象

// 覆写XMLHttpRequest API
if(!window.XMLHttpRequest) return;
  var xmlhttp = window.XMLHttpRequest;
  var _oldSend = xmlhttp.prototype.send;
  var _handleEvent = function (event) {
      if (event && event.currentTarget && event.currentTarget.status !== 200) {
        report(event)
      }
  }
  xmlhttp.prototype.send = function () {
      if (this['addEventListener']) {
          this['addEventListener']('error', _handleEvent);
          this['addEventListener']('load', _handleEvent);
          this['addEventListener']('abort', _handleEvent);
          this['addEventListener']('close', _handleEvent);
      } else {
          var _oldStateChange = this['onreadystatechange'];
          this['onreadystatechange'] = function (event) {
              if (this.readyState === 4) {
                  _handleEvent(event);
              }
              _oldStateChange && _oldStateChange.apply(this, arguments);
          };
      }
      return _oldSend.apply(this, arguments);
  }

// 覆写fetch API
if (!window.fetch) return;
var _oldFetch = window.fetch;
window.fetch = function() {
  return _oldFetch
    .apply(this, arguments)
    .then(function(res){
      if (!res.ok) {
        // True if status is HTTP 2xx
        report(res)
      }
      return res;
    })
    .catch(function(error){
      report(res)
    });
}

日志上报的方式

  • 异步请求上报, 后端提供接口,或者直接发到日志服务器

  • img请求上报, url参数带上错误信息

    • eg:(new Image()).src = 'http://baidu.com/tesjk?r=tksjk'

注意跨源脚本异常

当加载自不同域的脚本中发生语法错误时,为避免信息泄露,语法错误的细节将不会报告,而代之简单的 “Script error.”

由于同源策略影响,浏览器限制跨源脚本的错误访问,这样跨源脚本错误报错信息如下图:

跨源的脚本的异常

在H5的规定中,只要满足下面俩个条件,是允许获取跨源脚本的错误信息的。

  1. 客户端在script标签上增加crossorigin属性;
  2. 服务端设置js资源响应头Access-Control-Origin:*(或者是域名)。

扩展阅读

业界已经有的监控平台

  • Sentry开源
  • 阿里的ARMS
  • fundebug
  • FrontJS

几个异常监控的问题

  • 如何保证大家提交的代码是符合预期的? 如何了解前端项目的运行是否正常,是否存在错误?

    代码质量体系控制和错误监控以及性能分析

  • 如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?先想一下为什么会白屏?

    我们以用户访问页面的过程为顺序,大致排查一下

    1. 用户没打开网络
    2. DNS域名劫持
    3. http劫持
    4. cdn或是其他资源文件访问出错
    5. 服务器错误
    6. 前端代码错误
    7. 前端兼容性问题
    8. 用户操作出错

通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息

    1. 当前的网络状态
    2. 运营商
    3. 地理位置
    4. 访问时间
    5. 客户端的版本(如果是通过客户端访问)
    6. 系统版本
    7. 浏览器信息
    8. 设备分辨率
    9. 页面的来源
    10. 用户的账号信息
    11. 通过performance API收集用户各个页面访问流程所消耗的时间
    12. 收集用户js代码报错的信息
  • 如果我们使用了脚本代码压缩,然而我们又不想将sourcemap文件发布到线上,我们怎么捕获到错误的具体信息?

  • CSS文件中也存在引用资源,@font-face, background-image …等这些请求错误该如何进行错误捕获?

总结

  • Web规范中相关前端异常

  • 异常按照捕获方式分类

    • 运行时异常
    • 资源加载异常
    • 异步请求异常
    • Promise异常
  • 异常的捕获方式

    • try-catch (ES提供基本的错误捕获语法)

      • 只能捕获同步代码的异常
      • 回调
      • setTimeout
      • promise
    • window.onerror = cb (DOM0)

    • window.addEventListener(‘error’, cb, true) (DOM2)

    • window.addEventListener(“unhandledrejection”, cb) (DOM4)

    • Promise.then().catch(cb)

    • 封装XMLHttpRequest&fetch | 覆写请求接口对象

注意点:跨源脚本异常的捕获

原文链接:https://segmentfault.com/a/1190000016959011

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-44960.html

文章标题:前端异常监控-看这篇就够了

相关文章
前端MV*框架的意义
经常有人质疑,在前端搞MV有什么意义?也有人提出这样的疑问:以AngularJS,Knockout,BackBone为代表的MV框架,它跟jQuery这样的框架有什么区别?我jQuery用得好好的,有什么必要再引入这种框架? 回答这些问题之...
2016-03-11
前端问答社区成立了
由雷锋网友提供的给大家相互交流的前端问答社区正式上线了,欢迎大家来此相互交流相互学习 ...
2016-03-30
JavaScript初学者必看“箭头函数”
本文我们介绍箭头 (arrow) 函数的优点。 更简洁的语法 我们先来按常规语法定义函数: function funcName(params) { return params + 2; } funcName(2); &#x2F;&#...
2017-05-26
WebSocket断开原因分析,再也不怕为什么又断开了
阅读原文:https://wdd.js.org/websocket-… 1. 把错误打印出来 WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来。 在线demo地址:https://wdd.js.org/we...
2018-04-25
百度新功能【特效搜索】演示 惊呆了小伙伴
百度搜索最近又出新玩意新功能了,可能你还没有发现,名为【百度特效搜索】已经默默上线了,有什么效果呢? 在百度搜索中根据用户搜索的关键词来出发某些动作,例如笔者搜索“打雷”关键字,在搜索结果中你会听到有打雷声, 黑洞,闪烁、翻转、跳跃,打雷,...
2015-11-12
2014年,你是不是被这5个HTML5技术刷屏了?
如今,几乎每天都有HTML5页面的推广以及小游戏、小测试在微信上传播,用户也逐渐习惯被各种HTML5轰炸。那么在刚刚过去的一年究竟有哪些HTML5技术堪称火爆,让人们的微信频频被刷屏呢? 1、2048 2048 在4x4的棋盘上,用方向键选...
2015-11-12
为什么AngularJS能够成功?
AngularJS 为什么成功了? 写在前面的话 继上一篇总结之后, 觉得必须补充一下 AngularJS 与 Ionic 的技术性话题 于是, 连夜写了这第一篇. 讲述了 AngularJS 与其他对手之间的优与缺. 我有任何理解错误, ...
2015-11-12
前端工程师应该具备的三种思维
如果你是一个天才等级的工程师(马上可以离开),可以独立完成一个很多事情,你可以是一个怪咖,因为我相信没有一个人不会不佩服你。但现实归现实,多数人都不是天才,而我们在职场上也不是单打独斗,我们需要团队合作,需要协调和配合,需要考虑除了代码以外...
2016-01-13
微信火了HTML5,技术革新才是未来
Html5小游戏自从诞生以来,以其玩法简单、内容娱乐等特点,而深受玩家的欢迎。就像音乐领域的《小苹果》和《最炫名族风》一样,Html5小游戏也曾经有多款神作,在微信朋友圈如病毒式疯传。 微信让H5火了 去年,H5游戏“围住神经猫”上线微信朋...
2015-11-12
梳理前端开发使用eslint-prettier检查和格式化代码
问题痛点 在团队的项目开发过程中,代码维护所占的时间比重往往大于新功能的开发。因此编写符合团队编码规范的代码是至关重要的,这样做不仅可以很大程度地避免基本语法错误,也保证了代码的可读性。 对于代码版本管理系统(svn 和 git或者其他)...
2018-05-07
回到顶部