星图导航
首页 文章 排行榜 申请收录 友链申请 关于
首页 / 文章资讯 / 网站运营 / 用户白屏了你怎么知道:前端错误监控入门

用户白屏了你怎么知道:前端错误监控入门

星图导航配图

最难受的一种情况是:用户跟你说网站打不开了,你打开一看好好的。因为他的浏览器报了个错,这个错只发生在他那台设备上,服务器日志里干干净净,什么都没记下来。前端错误监控要解决的就是这件事。

为什么服务器日志里看不到前端错误

服务器日志记录的是请求。用户打开页面,服务器返回 200,日志里就是一条 200。至于返回去的代码在他电脑上跑起来报没报错,服务器完全不知道。

前端报错发生在浏览器里,浏览器不会主动告诉服务器。除非你在代码里主动上报,否则这个错误就消失了。

这就导致一个很常见的误判:监控面板上一切正常,用户却在骂你。你去看日志,找不到任何异常,最后只能猜。

要解决就得在页面里埋一段代码,浏览器一报错就往你的服务器发一条记录。这就是前端错误监控的最基本形态。

window.onerror 能抓到什么

最基础的一行代码是监听 window 的 error 事件。同步代码抛出的异常、脚本里的语法错误,都会触发它。

回调里能拿到三样关键信息:错误消息、出错的文件地址、行号和列号。有这三样,多数问题能直接定位到具体代码行。

要注意行号经常对不上,因为代码经过压缩或者合并,真实行号和你源文件的行号差很远。生产环境建议保留 sourcemap,或者至少在构建时不要做极致的变量混淆,否则错误信息全是单字母变量名,没法看。

另外这个事件在有些浏览器里对跨域脚本的错误只给一个笼统的 Script error,拿不到细节。解决办法是给脚本标签加 crossorigin 属性,并且服务器返回合适的 CORS 头。

这几种错误它抓不到

第一种是 Promise 里的错误。异步链里抛出的异常不会走 window.onerror,要单独监听 unhandledrejection 事件。这是现在最容易漏的一类,因为前端代码大量用 async。

第二种是资源加载失败。图片 404、脚本加载不上、字体下载失败,这些不抛异常,但它们会触发元素上的 error 事件。要单独给这些标签挂监听,或者在 window 上捕获阶段监听。

第三种是接口请求失败。fetch 或者 ajax 返回 500,代码里如果写了 catch,错误就被你吞掉了,监控看不到。要在统一的请求封装里主动上报。

第四种是用户主动关闭页面、网络断了。这类不算错误,但如果你的页面依赖某个请求成功才能渲染,表现出来就是白屏,得靠业务层面的心跳来发现。

上报怎么做才不拖慢页面

第一原则是异步、不阻塞。别在错误回调里同步发请求,那会让主线程卡住。用 navigator.sendBeacon,它在页面关闭时也能把数据发出去。

第二原则是限流。一个循环里报错几百次,你的上报接口会被打爆,服务器日志也会被刷满。做个简单的去重,同一个错误消息加同一个位置,一分钟内只报一次。

第三原则是控制体积。别把整个调用栈、整个页面状态都传上去,一条控制在几百字节。字段只留必要的:消息、文件、行号、页面地址、用户标识、时间。

第四原则是别在错误处理里再抛错误。上报代码本身要包一层 try catch,它挂了不能影响页面。

还有一点,上报接口要放在你自己的域名下,别直接往第三方域名打。跨域请求容易被拦,而且用户装个广告拦截插件就把上报屏蔽了。

去重和采样,别让数据淹死你

真实站点的错误量往往比你想的大得多。几百个用户在同一个老版本浏览器上触发同一个兼容问题,你的后台一天能收几万条,全是同一件事。

做法是按错误的指纹聚合。指纹可以用消息加文件加行号算一个哈希,同指纹的只累加次数,不重复存明细。

采样是另一招。量特别大的站可以只上报百分之一,够看出趋势。个人站用户不多,别采样,全收,一条都不能漏。

还要设一个阈值告警。同一个错误十分钟内出现超过五十次,就给你发通知。这种突增通常意味着刚上线的功能有严重问题。

自建还是用第三方

第三方的优势是开箱即用,界面好看,聚合去重都做好了。缺点是要把用户的部分数据发给别人,而且免费额度通常很小,超了就得付费。

自建的优势是完全可控,数据留在自己服务器,成本几乎为零。缺点是要自己写接收接口、自己写展示页面。

如果只是想“知道有没有错”,自建一个最简单的版本就够:一个接收接口把数据写进数据库,一个后台页面按时间倒序列出来,带个按消息分组的统计。

接收接口要注意两件事:一是要做频率限制,防止被人恶意刷;二是要校验来源,只接受你自己域名的上报,别成了公开的垃圾场。

收到错误之后怎么定位

拿到一条错误记录,先看它影响多少人。只有一个人报的,可能是他的浏览器或者网络问题;几十个人同时报的,基本是你的代码。

然后看时间分布。集中在某个时间点爆发,多半和那次上线有关,直接去看那个时间点改了哪些文件。

再看页面分布。只在某一个页面出现,问题就在那个页面的代码;所有页面都出现,多半是公共脚本或者公共组件的问题。

最后才是看具体报错。注意区分“代码 bug”和“环境问题”:报 undefined is not a function,通常是代码;报某个老浏览器不支持的语法,是兼容性。

定位完之后,修完一定要回看这个错误的曲线有没有归零。没归零说明你的修复没覆盖到所有场景,或者还有别的入口在触发同一个问题。