最近我们团队遇到了一次前端错误追踪系统的故障,整个过程惊心动魄,熬了两个通宵才解决,印象非常深刻。
事情是这样的,我们用Sentry做前端错误追踪,有一天突然发现,Sentry里的错误量暴增,但是我们的前端代码并没有发布新版本,也没有做什么改动,错误量怎么会突然暴增呢?而且更奇怪的是,这些错误都是同一个错误,但是堆栈信息很奇怪,看不出来是哪里的问题。
今天这篇文章,就来复盘一下这次故障的整个过程,聊聊我们是怎么排查的,遇到了哪些坑,最后是怎么解决的,以及一些经验总结,希望能给做前端监控和错误追踪的朋友一些参考。
一、故障发生
先说说故障是怎么发生的。
那天早上,我刚到公司,打开电脑,就收到了Sentry的告警邮件,说我们的前端项目错误量超过了阈值,需要关注。我打开Sentry一看,吓了一跳,错误量比平时高了几十倍,而且还在持续增长,大部分错误都是同一个错误,错误信息是"Script error.",堆栈信息只有一行,看不出来是哪里的问题。
我第一反应是,是不是前端代码出问题了?但是我看了一下,我们最近没有发布新版本,上一次发布还是一周前,而且发布之后一直很稳定,没有什么问题。那为什么错误量会突然暴增呢?
我又看了一下错误的分布,发现这些错误主要集中在几个页面,而且都是移动端的,PC端的错误很少。错误的浏览器分布也很奇怪,大部分都是一些很冷门的浏览器,或者是很低版本的浏览器,正常用户用的Chrome、Safari、微信内置浏览器这些,错误量反而不多。
这时候我意识到,这可能不是我们代码的问题,可能是外部因素导致的,比如第三方脚本、浏览器插件、网络劫持等。但是具体是什么原因,还需要进一步排查。
于是,我立刻召集了团队的几个同学,一起排查这个问题,一场惊心动魄的故障排查就这样开始了。
二、排查过程
第一步:确认错误是不是真实的用户错误
首先,我们要确认,这些错误是不是真实的用户错误,还是Sentry的误报,或者是爬虫、机器人产生的错误。
我们先看了一下错误的用户信息,发现这些错误对应的用户,很多都是没有登录的,而且用户的行为很奇怪,有的用户一进页面就报错,然后就离开了,没有任何后续操作。还有的用户,IP地址是一些很奇怪的地方,或者是云服务器的IP。
我们怀疑,这些错误可能是爬虫或者机器人产生的,不是真实的用户。于是,我们加了一些过滤规则,把已知的爬虫和机器人的User-Agent过滤掉,再看错误量,确实减少了一些,但是还是有很多错误,说明不全是爬虫的问题,还有真实用户的错误。
我们又看了一下真实用户的错误,发现这些用户,很多都是用的一些很冷门的浏览器,或者是很低版本的安卓系统,还有的是用的一些第三方的APP内置浏览器。这些用户,可能是因为浏览器不支持我们用的一些JS语法或者API,导致报错。
但是,我们的代码已经做了兼容处理,用了Babel转译,也加了polyfill,理论上应该能兼容这些低版本浏览器的,为什么还会报错呢?而且,这些错误之前一直没有,为什么突然就出现了呢?
第二步:排查第三方脚本的问题
我们怀疑,可能是第三方脚本的问题。我们的页面里引入了很多第三方脚本,比如统计脚本、广告脚本、客服脚本、地图脚本等,这些第三方脚本,如果出了问题,也会报错,而且错误的堆栈信息可能会指向第三方脚本,而不是我们的代码。
但是,Sentry里的错误信息是"Script error.",没有具体的错误信息,也没有堆栈,这是因为浏览器的同源策略,跨域的脚本报错,浏览器不会暴露具体的错误信息,只会显示"Script error."。所以,如果是第三方脚本报错,Sentry里就会显示"Script error.",和我们看到的错误信息一致。
于是,我们开始排查第三方脚本。我们把页面里的第三方脚本列了一个清单,然后一个一个地临时禁用,看禁用哪个脚本之后,错误量会下降。
我们先禁用了广告脚本,错误量没有明显变化;然后禁用了统计脚本,错误量也没有变化;然后禁用了客服脚本,错误量还是没有变化;最后,我们禁用了一个地图脚本,错误量突然下降了很多,大部分错误都消失了。
我们终于找到了问题的根源,就是这个地图脚本。但是,这个地图脚本我们已经用了很久了,一直很稳定,为什么突然就出问题了呢?
第三步:深入排查地图脚本的问题
我们联系了地图脚本的服务商,问他们最近是不是做了什么改动,是不是发布了新版本。服务商说,他们最近确实发布了一个新版本,优化了一些功能,但是他们说新版本是兼容旧版本的,应该不会有问题。
我们让服务商提供了新版本的代码,然后我们自己测试了一下,发现新版本的代码里,用了一些比较新的JS语法,比如箭头函数、const、let、Promise等,这些语法在低版本浏览器里是不支持的。而且,他们的新版本没有做Babel转译,也没有加polyfill,直接就发布了,所以在低版本浏览器里就会报错。
但是,为什么之前没有这个问题呢?因为之前的旧版本是做了兼容处理的,支持低版本浏览器,所以没有问题。这次发布新版本,他们可能是为了代码简洁,去掉了兼容处理,直接用了新语法,结果在低版本浏览器里就报错了。
而且,更坑的是,他们的新版本是灰度发布的,只有一部分用户能拿到新版本,所以最开始的时候,错误量不是很多,我们没有注意到。后来,灰度的比例越来越大,拿到新版本的用户越来越多,错误量就暴增了,我们才发现问题。
找到原因之后,我们立刻让服务商回滚了旧版本,或者紧急发布一个兼容低版本浏览器的新版本。服务商回滚之后,错误量立刻就下降了,慢慢恢复到了正常水平。
但是,事情还没有结束,因为我们发现,虽然地图脚本的问题解决了,但是Sentry里还是有一些"Script error."的错误,虽然量不多,但是一直存在,而且这些错误不是地图脚本导致的。于是,我们继续排查,又发现了另一个问题。
第四步:排查网络劫持的问题
我们发现,剩下的这些"Script error."错误,大部分都是来自一些特定的地区,而且都是移动端的,PC端很少。我们怀疑,可能是网络劫持的问题,也就是用户的网络运营商,在页面里注入了一些脚本,比如广告脚本、弹窗脚本等,这些脚本如果出了问题,也会报错,而且因为是跨域注入的,也会显示"Script error."。
为了验证这个猜想,我们让那些报错的用户,提供了一下页面的源代码,我们看了一下,发现页面里确实被注入了一些奇怪的脚本,这些脚本不是我们的,也不是我们引入的第三方脚本,是被网络运营商注入的广告脚本。这些脚本,有的写得很烂,有语法错误,有的会调用一些不存在的API,所以就会报错。
这个问题,我们没办法直接解决,因为是网络运营商的问题,我们控制不了。但是,我们可以做一些缓解措施,比如:
- 页面启用HTTPS,HTTPS可以防止网络劫持,因为HTTPS的内容是加密的,运营商没办法注入脚本。我们之前有些页面是HTTP的,没有启用HTTPS,所以被劫持了,我们把这些页面都改成了HTTPS,被劫持的情况就少了很多。
- 配置CSP(内容安全策略),限制页面只能加载我们信任的脚本,不信任的脚本会被浏览器拦截,这样即使被注入了脚本,也不会执行,就不会报错了。
- 在Sentry里过滤掉"Script error."的错误,因为这些错误大部分都不是我们代码的问题,过滤掉之后,Sentry里的错误就更干净了,我们能更专注于我们自己代码的错误。
采取了这些措施之后,剩下的"Script error."错误也基本解决了,Sentry里的错误量恢复到了正常水平,这场惊心动魄的故障排查终于结束了。
三、遇到的坑
这次故障排查,我们遇到了很多坑,下面说说几个比较典型的。
坑一:"Script error."没有堆栈,很难排查
"Script error."是前端错误追踪里最让人头疼的错误,因为它没有具体的错误信息,也没有堆栈,根本看不出来是哪里的问题,排查起来非常困难。
这个问题的原因是浏览器的同源策略,跨域的脚本报错,浏览器为了安全,不会暴露具体的错误信息,只会显示"Script error."。所以,如果你的页面里引入了跨域的第三方脚本,这些脚本报错了,Sentry里就会显示"Script error."。
要解决这个问题,有几个方法:
- 给跨域的脚本标签加上crossorigin属性,并且服务器配置CORS,这样跨域脚本报错的时候,浏览器就会暴露具体的错误信息。但是,这个方法需要第三方脚本的服务器支持CORS,很多第三方脚本的服务器没有配置CORS,所以这个方法不一定能用。
- 把第三方脚本下载到自己的服务器上,变成同源的脚本,这样报错的时候就会有具体的错误信息。但是,这样做的话,第三方脚本的更新就需要自己维护,比较麻烦。
- 实在没办法的话,就只能在Sentry里过滤掉"Script error."的错误,或者单独统计,不要让它影响正常错误的监控。
坑二:第三方脚本灰度发布,我们不知道
这次故障,一个很大的坑就是,第三方脚本的服务商做了灰度发布,但是没有通知我们,我们完全不知道,所以最开始的时候,错误量不多,我们没有注意到,等灰度比例大了,错误量暴增了,我们才发现问题,这时候已经影响了很多用户了。
所以,对于重要的第三方脚本,我们一定要和服务商保持沟通,让他们在发布新版本之前通知我们,最好是能让我们先测试一下新版本,确认没问题之后再全量发布。而且,我们自己也要做好监控,一旦错误量有异常,立刻排查,不要等问题严重了才发现。
坑三:第三方脚本不做兼容,坑了我们的用户
另一个坑就是,第三方脚本的服务商,发布新版本的时候,不做低版本浏览器的兼容,直接用新语法,结果在低版本浏览器里报错,坑了我们的用户。我们的用户,因为第三方脚本的问题,页面报错,影响了正常使用,但是用户不知道是第三方脚本的问题,只会觉得是我们的网站有问题,对我们的品牌造成了不好的影响。
所以,对于第三方脚本,我们一定要做好评估,选择靠谱的服务商,不要随便引入不知名的第三方脚本。而且,对于重要的第三方脚本,最好是能自己控制版本,不要直接引用服务商的最新版本,而是引用一个固定的版本,服务商更新新版本之后,我们测试没问题了再切换,这样就不会因为服务商的更新导致我们的页面出问题。
坑四:HTTP页面被网络劫持,防不胜防
还有一个坑就是,HTTP页面很容易被网络运营商劫持,注入广告脚本,这些脚本不仅会影响用户体验,还可能报错,而且我们没办法直接控制,防不胜防。
这个问题,最好的解决方法就是全站HTTPS,HTTPS可以有效防止网络劫持,因为内容是加密的,运营商没办法篡改和注入。现在HTTPS已经很普及了,证书也很便宜,甚至有免费的证书,所以一定要尽快把全站改成HTTPS,不要用HTTP了。
除了HTTPS,还可以配置CSP,进一步限制页面只能加载信任的脚本,即使被注入了脚本,也不会执行。CSP是一个很强大的安全功能,能有效防止XSS和脚本注入,建议大家都配置一下。
四、经验总结
这次故障,虽然折腾了两个通宵,但是也让我们学到了很多,总结了一些经验,分享给大家。
1. 前端错误追踪很重要,一定要做好
这次故障,我们能这么快发现问题,就是因为我们做了前端错误追踪,用Sentry监控前端的错误,错误量异常的时候立刻告警。如果没有错误追踪,我们可能很久都发现不了这个问题,会影响更多的用户。
所以,前端错误追踪真的很重要,一定要做好,选择一个靠谱的错误追踪工具,比如Sentry、Fundebug、Bugly等,配置好告警规则,错误量异常的时候立刻通知相关人员,及时排查和解决问题。
2. 第三方脚本是风险点,一定要管控好
第三方脚本是前端的一个重要风险点,因为第三方脚本不受我们控制,服务商的任何改动,都可能影响我们的页面。所以,对于第三方脚本,一定要管控好。
具体的措施包括:
- 尽量少用第三方脚本,能用自己实现的就自己实现,减少依赖。
- 必须用的第三方脚本,选择靠谱的服务商,不要用不知名的小服务商。
- 重要的第三方脚本,固定版本,不要直接引用最新版本,服务商更新之后,测试没问题再切换。
- 和服务商保持沟通,发布新版本之前让他们通知我们,最好能让我们先测试。
- 做好第三方脚本的监控,一旦第三方脚本报错或者加载失败,立刻告警。
3. "Script error."要单独处理,不要和正常错误混在一起
"Script error."是前端错误追踪里很常见的错误,大部分都不是我们代码的问题,而是第三方脚本或者网络劫持导致的。所以,要把"Script error."单独处理,不要和正常错误混在一起,不然会干扰我们对正常错误的监控,也会导致错误量虚高,告警不准确。
可以在Sentry里配置过滤规则,把"Script error."的错误过滤掉,或者单独放到一个项目里统计,这样Sentry里的错误就更干净了,我们能更专注于我们自己代码的错误。
4. 全站HTTPS和CSP,一定要配置
全站HTTPS和CSP,是前端安全的基础配置,能有效防止网络劫持和XSS攻击,也能减少很多"Script error."的错误。现在HTTPS和CSP都已经很普及了,配置也不复杂,所以一定要尽快配置好,不要偷懒。
5. 故障排查要系统,不要盲目猜测
这次故障排查,我们最开始也走了一些弯路,盲目猜测是我们代码的问题,查了很久都没查到原因。后来,我们系统地分析了错误的特征,比如错误的页面分布、浏览器分布、用户分布等,慢慢缩小了范围,最后才定位到是第三方脚本的问题。
所以,故障排查一定要系统,不要盲目猜测,要先收集信息,分析错误的特征,缩小范围,然后一步步排查,这样才能高效地找到问题的根源。
6. 故障复盘很重要,要总结经验教训
故障解决之后,一定要做复盘,总结经验教训,避免以后再犯同样的错误。这次故障之后,我们做了详细的复盘,总结了很多经验,也优化了我们的监控和第三方脚本管理流程,避免以后再出现类似的问题。
故障复盘,不是为了追究谁的责任,而是为了从故障中学习,提升团队的技术能力和应急响应能力,避免以后再出现类似的故障。所以,每次故障之后,都要认真做复盘,总结经验教训,持续改进。
五、写在最后
这次前端错误追踪的故障,整个过程惊心动魄,熬了两个通宵才解决,但是也让我们学到了很多,提升了团队的故障排查能力和应急响应能力,也优化了我们的前端监控和第三方脚本管理流程。
前端的世界,比后端复杂得多,因为前端运行在用户的浏览器里,环境千差万别,有各种各样的浏览器,各种各样的网络环境,各种各样的第三方脚本,还有网络劫持、浏览器插件等不可控的因素,所以前端的问题,往往比后端更复杂,更难排查。
但是,只要我们做好监控,做好管控,系统地排查问题,认真总结经验,就能应对各种前端故障,保证前端的稳定和用户体验。
希望这篇复盘文章,能给做前端监控和错误追踪的朋友一些参考,也希望大家都能少踩坑,少熬夜,写出更稳定的前端代码。
最后,提醒大家,前端无小事,每一个细节都可能影响用户体验,一定要重视前端的监控和质量,给用户提供更好的体验。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录