Vue.config.errorHandler = function (err, vm, info) {
let {
message, // 异常信息
name, // 异常名称
script, // 异常脚本url
line, // 异常行号
column, // 异常列号
stack // 异常堆栈信息
} = err;
// vm为抛出异常的 Vue 实例
// info为 Vue 特定的错误信息,比如错误所在的生命周期钩子
}
script line column目前是undefined,自行在statck中获取
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
this.setState({ hasError: true });
// 将异常信息上报给服务器
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
return '出错了';
}
return this.props.children;
}
}
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
react的获取
router.post('/errorMsg/', function(req, res) {
let error = req.body; // 获取前端传过来的报错对象
let url = error.scriptURI; // 压缩文件路径
if (url) {
let fileUrl = url.slice(url.indexOf('client/')) + '.map'; // map文件路径
// 解析sourceMap
let smc = new sourceMap.SourceMapConsumer(fs.readFileSync(resolve('../' + fileUrl), 'utf8')); // 返回一个promise对象
smc.then(function(result) {
// 解析原始报错数据
let ret = result.originalPositionFor({
line: error.lineNo, // 压缩后的行号
column: error.columnNo // 压缩后的列号
});
let url = ''; // 上报地址
// 将异常上报至后台
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
errorMessage: error.errorMessage, // 报错信息
source: ret.source, // 报错文件路径
line: ret.line, // 报错文件行号
column: ret.column, // 报错文件列号
stack: error.stack // 报错堆栈
})
}).then(function(response) {
return response.json();
}).then(function(json) {
res.json(json);
});
})
}
});
- 业务代码错误,这是比较特殊的,是开发者自己记录的错误。根据此错误,可以在线上定位具体业务逻辑,一般记录的时候会记录错误栈+错误文件和行数+上下文信息,例如参数之类的数据。
- 全局通用错误,例如发起请求的错误,例如 express 的中间件错误,例如数据库错误,缓存错误等,如果出现错误,会统一通过框架记录到日志中。
- 最后一道门,uncaughtException 和 unhandledRejection ,用来记录被忽略的可能导致应用 crash 的错误,例如直接 throw 出来的 Error 或者 语法错误等。对于 uncaughtException 我们的处理方式是捕获,然后记录日志,记录完毕,吞掉。晚上对于此种处理方式颇有异议,但是作为一个线上服务,crash 是非常严重的。but 一定要记住,在测试环境千万不要吞掉 uncaughtException,把错误暴露出来,并且直接 crash 掉,这样才能在开发和测试阶段排查出 crash 级别的错误。(此处大多数文章推荐出问题后重启而不是吞掉,我觉得这里值得商榷,不要简单定论,最终,快速修复问题才是王道,而不是做一堆假设)