JS错误处理:前端JS/Vue/React/Iframe/跨域/Node
前端  /  管理员 发布于 6年前   447
js错误捕获
js错误的实质,也是发出一个事件,处理他
error实例对象对象属性
message:错误提示信息对象类型(7种)
SyntaxError对象是解析代码时发生的语法错误自定义错误
function UserError(message) { this.message = message || '默认信息'; this.name = 'UserError';}UserError.prototype = new Error();UserError.prototype.constructor = UserError;new UserError('这是自定义的错误!');
try..catch…finally
范围:用来捕获任何类型的同步错误,可以捕获async / await的代码,但无法捕获promise、setTimeout、dom回调(eg:onclick点击回调)的代码,在回调函数里面写try…catch可以捕获,但包在外面不会捕获,无法捕获语法错误
异步不捕获原因:
async/await捕获原因:window.onerror
范围:同步错误和异步错误都可以捕获,但无法捕获到静态资源异常,或者接口异常(网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行),无法捕获语法错误
原理:当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件
参数
/*** @param {String} message 错误信息* @param {String} source 出错文件* @param {Number} lineno 行号* @param {Number} colno 列号
*/window.onerror = function(message, source, lineno, colno, error) { console.log('捕获到异常:',{message, source, lineno, colno, error});}```
补充:window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx
onerror 最好写在所有 JS 脚本的前面,否则有可能捕获不到错误;(捕获的是全局错误)
window.addEventListener(一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个 Event 接口的 error事件,并执行该元素上的onerror() 处理函数,有浏览器兼容问题)
注意:只能捕获无法冒泡
window.addEventListener('error', (error) => { console.log('捕获到异常:', error);}, true) // 一定要加true,捕获但不冒泡
Script error跨域的静态资源加载异常捕获(cdn文件等)
跨域文件只会报Script error,没有详细信息,怎么解决:
客户端:script标签添加crossOrigin
服务端:设置:Access-Control-Allow-Origin
<script src="http://jartto.wang/main.js" crossorigin></script>
使用window.onerror
<iframe src="http://www.fly63.com/article/detial/3373/./iframe.html" frameborder="0"></iframe><script> window.frames[0].onerror = function (message, source, lineno, colno, error) { console.log('捕获到 iframe 异常:',{message, source, lineno, colno, error}); return true; };</script>
没有写 catch 的 Promise 中抛出的错误无法被 onerror 或 try-catch 捕获到
为了防止有漏掉的 Promise 异常,建议在全局增加一个对 unhandledrejection 的监听,用来全局监听Uncaught Promise Error
window.addEventListener("unhandledrejection", function(e){ console.log(e);});
补充:如果去掉控制台的异常显示,需要加上:event.preventDefault();
vue errorHandler
Vue.config.errorHandler = (err, vm, info) => { console.error('通过vue errorHandler捕获的错误'); console.error(err); console.error(vm); console.error(info);}
componentDidCatch(react16)
新概念Error boundary(React16):UI的某部分引起的 JS 错误不会破坏整个程序(只有 class component可以成为一个 error boundaries)
不会捕获以下错误
1.事件处理器2.异步代码3.服务端的渲染代码4.在 error boundaries 区域内的错误
Eg: 全局一个error boundary 组件就够用啦
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; }}<ErrorBoundary> <MyWidget /></ErrorBoundary>
卡顿:网页暂时响应比较慢, JS 可能无法及时执行
解决:window 对象的 load 和 beforeunload 事件实现了网页崩溃的监控
window.addEventListener('load', function () { sessionStorage.setItem('good_exit', 'pending'); setInterval(function () { sessionStorage.setItem('time_before_crash', new Date().toString()); }, 1000); }); window.addEventListener('beforeunload', function () { sessionStorage.setItem('good_exit', 'true'); }); if(sessionStorage.getItem('good_exit') && sessionStorage.getItem('good_exit') !== 'true') { /* insert crash logging code here */ alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash')); }
崩溃:JS 都不运行了,还有什么办法可以监控网页的崩溃,并将网页崩溃上报呢
解决:Service Worker 来实现网页崩溃的监控
Service Worker 有自己独立的工作线程,与网页区分开,网页崩溃了,Service Worker一般情况下不会崩溃;
Service Worker 生命周期一般要比网页还要长,可以用来监控网页的状态;
网页可以通过 navigator.serviceWorker.controller.postMessage API 向掌管自己的 SW发送消息。
Ajax 发送数据
因为 Ajax 请求本身也有可能会发生异常,而且有可能会引发跨域问题,一般情况下更推荐使用动态创建 img 标签的形式进行上报。
动态创建 img 标签的形式 更常用,简单,无跨越问题
function report(error) { let reportUrl = 'http://jartto.wang/report'; new Image().src = `${reportUrl}?logs=${error}`;}
如果你的网站访问量很大,那么一个必然的错误发送的信息就有很多条,这时候,我们需要设置采集率,从而减缓服务器的压力:
Reporter.send = function(data) { // 只采集 30% if(Math.random() < 0.3) { send(data) // 上报错误信息 }}
js源代码压缩如何定位:成熟方案提供sentrysentry 是一个实时的错误日志追踪和聚合平台,包含了上面 sourcemap 方案,并支持更多功能,如:错误调用栈,log 信息,issue管理,多项目,多用户,提供多种语言客户端等,
这里不过多叙述,之后在搭建sentry服务时,会再补篇博文
补充:node服务端错误处理机制全栈开发,后端采用express库,在这里补充一下,node服务的错误处理方案
错误分类
一般错误处理:如某种回退,基本上只是说:“有错误,请再试一次或联系我们”。这并不是特别聪明,但至少通知用户,有地方错了——而不是无限加载或进行类似地处理
特殊错误处理为用户提供详细信息,让用户了解有什么问题以及如何解决它,例如,有信息丢失,数据库中的条目已经存在等等
步骤
1. 构建一个自定义 Error 构造函数:让我们方便地获得堆栈跟踪
class CustomError extends Error { constructor(code = 'GENERIC', status = 500, ...params) { super(...params) if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError) } this.code = code this.status = status }}module.exports = CustomError
2.处理路由:对于每一个路由,我们要有相同的错误处理行为
wT:在默认情况下,由于路由都是封装的,所以 Express 并不真正支持那种方式
解决:实现一个路由处理程序,并把实际的路由逻辑定义为普通的函数。这样,如果路由功能(或任何内部函数)抛出一个错误,它将返回到路由处理程序,然后可以传给前端
const express = require('express')const router = express.Router()const CustomError = require('../CustomError')router.use(async (req, res) => { try { const route = require(`.${req.path}`)[req.method] try { const result = route(req) // We pass the request to the route function res.send(result) // We just send to the client what we get returned from the route function } catch (err) { /* This will be entered, if an error occurs inside the route function. */ if (err instanceof CustomError) { /* In case the error has already been handled, we just transform the error to our return object. */ return res.status(err.status).send({ error: err.code, description: err.message, }) } else { console.error(err) // For debugging reasons // It would be an unhandled error, here we can just return our generic error object. return res.status(500).send({ error: 'GENERIC', description: 'Something went wrong. Please try again or contact support.', }) } } } catch (err) { /* This will be entered, if the require fails, meaning there is either no file with the name of the request path or no exported function with the given request method. */ res.status(404).send({ error: 'NOT_FOUND', description: 'The resource you tried to access does not exist.', }) }})module.exports = router// 实际路由文件const CustomError = require('../CustomError')const GET = req => { // example for success return { name: 'Rio de Janeiro' }}const POST = req => { // example for unhandled error throw new Error('Some unexpected error, may also be thrown by a library or the runtime.')}const DELETE = req => { // example for handled error throw new CustomError('CITY_NOT_FOUND', 404, 'The city you are trying to delete could not be found.')}const PATCH = req => { // example for catching errors and using a CustomError try { // something bad happens here throw new Error('Some internal error') } catch (err) { console.error(err) // decide what you want to do here throw new CustomError( 'CITY_NOT_EDITABLE', 400, 'The city you are trying to edit is not editable.' ) }}module.exports = { GET, POST, DELETE, PATCH,}
3.构建全局错误处理机制
process.on('uncaughtException', (error: any) => { logger.error('uncaughtException', error)})process.on('unhandledRejection', (error: any) => { logger.error('unhandledRejection', error)})
1.可疑区域增加 Try-Catch
2.全局监控 JS 异常 window.onerror
3.全局监控静态资源异常 window.addEventListener
4.捕获没有 Catch 的 Promise 异常:unhandledrejection
5.VUE errorHandler 和 React componentDidCatch
6.监控网页崩溃:window 对象的 load 和 beforeunload
7.跨域 crossOrigin 解决
原文来自:https://segmentfault.com/a/1190000019226851
122 在
学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..123 在
Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..原梓番博客 在
在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..博主 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..1111 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
Copyright·© 2019 侯体宗版权所有·
粤ICP备20027696号