Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端异常类型及捕获方式 #53

Open
XXHolic opened this issue Apr 18, 2020 · 0 comments
Open

前端异常类型及捕获方式 #53

XXHolic opened this issue Apr 18, 2020 · 0 comments

Comments

@XXHolic
Copy link
Owner

XXHolic commented Apr 18, 2020

目录

引子

最近想起这方面的事情,就去花时间查找了相关资料,以下是个人的总结。

异常类型

在使用浏览器,浏览一个网页,与网页进行交互的过程中,从用户的角度想一想会出现那些异常。

首先是使用浏览器一般都是基于操作系统,系统自身可能会出现问题,比如内存不够。这类情况归为系统异常

正常打开浏览器后,访问网页的时候,可能没有网络,或提示出现服务错误等等,这类情况归为网络异常

能够正常访问网页后,用户进行交互时,可能出现一种情况下点击有效,另一种情况下点击无效。这类情况归为应用异常

在上面感性的认知基础上,下面进一步进行细化。

系统异常

系统异常情况比较少,相关的可能有:

  • 浏览器崩溃

网络异常

网络异常中,相关的可能有:

  • XMLHttpRequest 请求异常
  • Fetch 请求异常
  • 静态资源加载异常

应用异常

应用异常可以用 JavaScript 中的错误对象体现出来:

  • EvalError : 与 eval() 有关的错误。
  • RangeError : 表示这个值不在允许值集或范围内。
  • ReferenceError : 表示发现一个无效的引用。
  • SyntaxError : 表示发生了解析错误。
  • TypeError :当其它类型错误都不符合时,TypeError 用于指示一个不成功的操作。
  • URIError :表示用于处理 URI 的函数(encodeURI 或 decodeURl)使用方式与其定义的不兼容。

比较常见的异常可以参考 Top 10 JavaScript errors from 1000+ projects

异常捕获

浏览器都具有某种向用户报告异常的机制,对于用户都是隐藏此类信息。对于开发者,一般在控制台可以看到相关信息。

下面看下捕获异常对应的方法。

try-catch 捕获

try-catch 使用的形式如下:

try {
  // 可能导致异常的代码
} catch(error) {
  // 发生异常时的处理
}

测试页面见这里,有下面的一些特点:

  • catch 块中会接收一个包含异常信息的对象,在不同的浏览器中包含的信息可能不同,但共同有一个保存异常信息的 message 属性。
  • 不能捕获语法异常。
  • 不能捕获异步异常。
  • 该方式捕获的异常,不会出现在控制台上,也不会被 error 事件捕获。

语法异常在开发的阶段就很容易发现,例如:

try {
  var num = '333;
} catch(error) {
  console.info('try-catch:', error);
}

不能捕获异步异常示例如下:

try {
  setTimeout(() => {
    name.forEach(() => {});
  },1000)
} catch(error) {
  console.info('try-catch:', error);
}

try-catch 比较适合用在那些可以预见可能出错的地方。

error 事件捕获

通常将这个事件绑定在 window 上,但由于历史原因,使用 DOM 不同级别的绑定方式,会有些差别。测试页面见这里

DOM0 级方式

也就是使用 window.onerror 指定处理程序,其特点有:

  • 参数有 5 个,对应含义分别为 message — 错误信息(字符串)、source — 发生异常的脚本URL(字符串)、lineno — 发生异常的行号(数字)、colno — 发生异常的列号(数字)、error — Error 对象。
  • 函数体内用 return true 可以阻止异常信息出现在控制台。
  • 可以捕获到异步异常。
  • 不能捕获到语法异常。
  • 不能捕获 try-catch 中的异常。
  • 不能捕获 scriptimginputaudiosourcetrack 标签元素 src 属性的加载异常(HTML5 不支持的 frame 标签不讨论)。测试页面见这里
  • 不能捕获 link 标签的加载异常,测试页面间这里这里

DOM2 级方式

也就是使用 window.addEventListener 指定处理程序,其特点有:

  • 参数对应 1 个,是一个 ErrorEvent 对象,其中包含信息相对 DOM0 级更加丰富。
  • 函数体内用 preventDefault() 方法可以阻止异常信息出现在控制台,但如果是加载资源异常无法阻止。
  • 可以捕获 scriptimginputaudiosource 标签元素 src 属性的加载异常(track 尝试了一下不行)。由于加载请求不会冒泡,所以需要在事件的捕获阶段监听才行。但这种方式无法知道 HTTP 的相关状态。测试页面见这里
  • 可以捕获 link 标签的加载异常,测试页面间这里这里
  • 可以捕获异步异常。
  • 不能捕获到语法异常。
  • 不能捕获到 try-catch 中的异常。

onerror 事件比较适合捕获预料之外的异常。

Promise、Async/Await 异常捕获

Async 函数返回的总是一个 Promise ,如果 Async 函数里面有异常,Promisereject 。所以统一的放到 Promise 里面的 catch 处理会比较方便。其特点:

  • 没有写 catchPromise 无法被 onerrortry-catch 捕获,测试页面见这里
  • Promisereject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件 unhandledrejection
  • 写了 catch 后,不会触发 unhandledrejection 事件,所以建议全局增加这个事件监听。
  • 本地测试验证的时候,注意跨域的限制,见 issues1issues2

XMLHttpRequest 请求异常捕获

XMLHttpRequest 目前来说应用非常广泛,有对应的 error 事件可以进行监听。在实际中,有可能团队内已有约定的一套异常状态码,可根据实际情况进行对应的处理。这是简单示例

Fetch 请求异常捕获

Fetch API 提供了一个获取资源的接口。它对于使用过 XMLHttpRequest 的人来说会很类似,但这个新的接口提供了更加强大的功能。有下面的一些点需要注意:

  • fetch 方法返回的是一个 Promise ,因此可以使用 catch 进行异常捕获。
  • 当接收到一个代表错误的 HTTP 状态码时,fetch 返回的 Promise 不会 reject ,即使响应的 HTTP 状态码是 404 或 500。相反,它会 resolve ,但会将 resolve 返回值的 ok 属性设置为 false ,仅当网络故障或请求被阻止时,才会 reject 。这是请求为 404 的示例

iframe 异常捕获

error 事件可以捕获到一些标签的 src 加载异常,但 iframe 的情况有些不一样。在网上找了一些资料,尝试了下面的一些方法:

  • 使用 window.onerror 方式,无法捕获,这是测试页面
  • 使用 window.frames[0].onerror 方式,无法捕获,这是测试页面
  • 在标签上绑定 onerror 事件,没有触发,无法捕获,这是测试页面
  • 绑定 onload 事件,可以触发,但无法直接的捕获,例如一般的网站都设置了 404 页面,当 src 加载的一个网页找不到时,就会默认使用 404 网页,虽然触发了 onload 事件,但仍然不知道是不是异常。这个时候,可以通过间接的检测这个显示 404 页面的一些信息,来判断是否异常,比如当发现这个页面 title 里面有 404 或者 not found 之类的词汇,那就说明 iframe 加载异常。这个根据实际情况,可以设置其它检测的标识。这是测试页面

还有一种思路就是用一个异步请求,让服务器端判断一下是否能够正常的访问 src 的资源,如果请求返回正常,那就直接动态设置 src 的值,否则就是异常情况,直接上报即可。

跨域

跨域的出现是由于浏览器的同源策略,一旦发生,会在控制台出现很明显的提示。通过查找资料发现,更多的方案是提前解决这个问题,但也有针对特定的情况进行捕获的方法。下面是相关的资料:

参考资料

🗑️

看了一个纪录片《走进黑暗网络》,发现两个比较有趣的东西:

  • 里面说的可以防止第三方追踪分析的浏览器名叫 Tor
  • 可以匿名公开爆料的网站维基解密

53-poster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant