版权声明:本文为博主原创文章,未经博主允许不得转载。 文章底部留言可联系作者。
一、背景
在开发过程中发现页面上 antd 的表单 onFinish 方法中的js错误不能正常上报,先开始以为是被react捕获了没有再抛出,所以window.onerror捕获不到,查看了一些相关的文章
import { Form, Divider, Input, Button } from "antd";
export default function App() {
// onFinish事件错误可window.onerror不能捕获
const onFinish = (values) => {
a;
};
return (
<div className="App">
<Form
...
onFinish={onFinish}
>
...
<Form.Item>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
</div>
);
}
后来断点发现是antd的onFinish方法内部try catch 捕获了错误然后 console.error 打印的。
为了可以顺利上报就想到了重新console.error 并在重写的方法里直接上报。
二、重写console.error
因为antd中是通过 try catch 捕获的error,获取error中的信息 主要包含:
try {
// ...
} catch(err) {// <-- “error 对象”,也可以用其他参数名代替 err
// ...
}
-
nameError 名称。例如,对于一个未定义的变量,名称是
"ReferenceError"。 -
message关于 error 的详细文字描述。
-
stack当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
try {
lalala; // error, variable is not defined!
} catch(err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)
// 也可以将一个 error 作为整体显示出来as a whole
// Error 信息被转换为像 "name: message" 这样的字符串
alert(err); // ReferenceError: lalala is not defined
}
我们了解到我们 console.error 中打印的是什么以后就可以针对的重写并上报这个错误了
// 重写console.error
const oldError = console.error;
console.error = function (error) {
if (error != '参数有缺失') {
const message = error.message;
const stack = error.stack;
let row = 0, column = 0, url = null;
if (stack) {
let mres = stack.match(/\(.*?\)/g) || []
let firstLine = (mres[0] || "").replace("(", "").replace(")", "") // 获取到堆栈信息的第一条
// 根据:分隔获取行列
let info = firstLine.split(':')
row = info[info.length - 2] // 行
column = info[info.length - 1] // 列
// 获取报错文件url
url = [...info].slice(0, info.length - 2).join(':');
}
setTimeout(function () {
// 上报错误内容
let opt = {
url,
row,
column,
message,
stack // 错误堆栈信息
}
//进行上报的方法
...
}, 0);
}
return oldError.apply(console, arguments);
};
三、其他
- 除了上面提到的
antd onFinish捕获了错误导致window.onerror无法捕获到之外,在普通的onClick事件中发现是不受影响的。
import { Button } from "antd";
...
// 普通点击事件错误可以通过window.onerror捕获
const clickHandler = () => {
b;
};
return (
<Button onClick={clickHandler}>测试普通点击</Button>
)
- react组件渲染导致的报错,因为使用了错误边界(
ErrorBoundary)我们可以看到react内部也会console.error打印的错误,但是并没有捕获
export default function App() {
...
cccc //这里会渲染的时候报错
return (
<div className="App">
...
</div>
);
通过打印的堆栈信息点击进去我们看一看到打印报错的地方: