只有特定浏览器报JS错误?按版本下钻的排查路径

作者:456数据 发布:2026-09-30 16:33 浏览量:0 来源:原创

周一早上九点十五分,我刚倒上咖啡,告警群就先炸了:JS 错误量在过去四十分钟里翻了三倍。值班群里有人甩来一张监控曲线——报错像被人从底下顶了一下。但奇怪的是,客服侧的用户投诉并没同步上涨,产品同学也说核心下单链路看上去正常。这种“监控在叫、用户没叫”的错位,是前端工程师最熟悉的一种早晨。

我通常不会这时立刻打开编辑器翻代码。“报错量整体飙升”和“某一类用户在某一类页面集中报错”是两件事:前者往往是一次发布引入的全站问题,后者更可能是某个浏览器版本的兼容问题。方向不同,排查路径完全不同。所以正确的第一步,不是去找代码,而是先把范围缩小。

一、先分清这是“面”还是“点”

面对一条突然抬头的报错曲线,先问两个问题:一是报错有没有跟着某次发布走,二是是不是只落在某几个浏览器里。全站浏览器都在报,大概率是刚发的版本自己出了问题,应当优先考虑回滚;只有某个浏览器版本在报、其他浏览器曲线平稳,更像是兼容性问题,不必回滚全站。之所以先做这个判断,是因为回滚的成本远大于定位一个兼容问题——判断错方向,整支团队的早晨都会被拖垮。

报错量在某浏览器版本灰度放量时段出现尖峰,其他浏览器保持平稳

这里有个小经验:真遇到这种早晨,不要一上来就盯堆栈。堆栈是最后才该看的东西——它告诉你代码在哪,却不告诉你为什么偏偏是这批用户在报错。先看版本分布,五分钟就能判断要不要回滚;先盯堆栈,可能会在一堆压缩后的行列号里耗掉一上午。排查顺序错了,时间就先没了。

二、用三个维度交叉,把“谁在错”切出来

确认是“点”问题之后,下一步就是下钻。我在前端监控里按浏览器版本筛了一下报错,再按三个维度逐层收窄:浏览器及版本、页面 URL、错误堆栈。这三个维度不是并列看一眼,而是层层相交:先圈浏览器版本,再在这个圈里看页面,最后看堆栈。收敛后样本才足够小、足够具体,才值得打开 DevTools 去复现。

1. 浏览器及版本:先看是不是某内核版本引入

先说清采集参数,避免一个常见误会:window.onerror 的回调签名是 (message, source, lineno, colno, error),对应报错信息、源码 URL、行号、列号和 Error 对象——并不是“第一个参数就是 UA”。真正的 UA(用户代理字符串)并不在这个签名里,需要监控脚本另外从 navigator.userAgent 读取,再解析成浏览器与版本号。把版本分布拉出来看一眼,异常往往立刻现出原形:错误是不是集中在某一个版本号上,是不是和该版本的灰度放量时间对齐。报错从 09:20 抬头、新版本灰度也从 09:20 放量——时间一对上,方向就基本锁定。

2. 页面 URL:再看是不是某条路由在错

锁定浏览器版本之后,把样本按页面 URL 聚合。同一段脚本会在很多页面运行,报错通常只集中在某一个路由或 H5 页面上。按页面收敛后,绝大部分报错其实挤在结算页一个页面,其余只是零星波及。这一步把排查面从“全站”压回到“一个页面”。

3. 错误堆栈:最后看是不是同一段代码

同一种报错会被记成很多条日志,却未必是同一处问题。要按 error.stack 做指纹聚类:把堆栈前几帧相同的样本归成一类。收敛后只剩两三类堆栈,说明问题集中在一两段代码;仍是几十种零散堆栈,更像随机的第三方脚本或浏览器扩展注入,方向又要换。

下钻维度这一步看什么能排除什么它不做什么
浏览器及版本错误在各浏览器版本上的分布与发布时间对齐排除全站发布问题,锁定是否单一内核版本引入不判断是哪个 API 不兼容
页面 URL报错在各路由 / H5 页面上的聚合计数排除无关页面,把范围压到少数页面不指出页面里哪段脚本
错误堆栈按 error.stack 前几帧指纹聚类区分是一两处代码问题还是多处零散报错不自动映射回源码行号
四个维度逐层相交,样本从全量收敛到一小簇具体问题

三、这些数据到底是怎么被采上来的

有必要把采集机制讲清楚,否则容易对监控能力产生误会。前端 JS 错误主要靠两类全局事件捕获:window.onerror 捕获运行时同步抛出的错误,unhandledrejection 捕获没有被 catch 的 Promise 拒绝,回调里主要提供 promise 对象与 reason。之所以要同时监听两者,是因为现代前端大量逻辑是异步的,只挂 window.onerror 会漏掉相当一部分 Promise 报错。还要强调:UA 并不在这两个回调的参数里,得由监控脚本自己从 navigator.userAgent 读取,连同报错信息、页面 URL 与时间戳一并上报。

捕获方式能抓到什么抓不到什么
window.onerror同步运行时错误、语法错误、资源加载异常的回调入口未被 catch 的 Promise 拒绝
unhandledrejection异步 Promise 里没有捕获的 rejection 原因已经被 try/catch 或 .catch 处理掉的错误

这里要特别说清楚 sourcemap。线上代码经过压缩混淆,error.stack 里的行列号指向压缩后的文件,没法直接读。要在构建产物发布后把 sourcemap 放到离线环境,用专门工具把压缩堆栈映射回源码行号。这一步离线、由研发自己完成;平台不会、也不该自动把源码上传到服务端还原。理解这点很重要——它决定了你不能指望监控平台直接告诉你“第几行第几列出错”。

还要提醒一点:UA 解析本身并不完美。很多内置浏览器和 WebView 会在 UA 里混入自己的标识,同一款 App 不同版本的 UA 格式还会变;按版本下钻时,不妨把命中特别小、明显是解析噪音的版本先忽略,否则会在边角样本上浪费注意力。

四、缩小范围之后,剩下的事交给 Chrome DevTools

到这一步,监控能做的已经做完了:它把“全站报错”收敛成“某个浏览器版本、某个页面、某类堆栈”的一小簇样本。但根因到底是什么——是某个新 API 在该版本不存在,还是某个变量在特定内核下为 undefined——监控曲线本身回答不了。因为这类问题依赖实时断点、作用域查看和在那个具体浏览器里的复现,剩下的工作要在真实目标环境里完成:在目标浏览器/版本、远程真机或浏览器云(如 BrowserStack)里打开那个页面,在堆栈指向的位置下断点,看变量在哪一步变了。这里有个误区:不要在 DevTools 里把 UA 字符串切成目标版本来复现——UA 覆盖只改了上报给服务端的 User-Agent,并不改变 Chrome 自身的内核与 JS 引擎实现,用它复现内核级错误只会得到假复现。DevTools 的 UA 模拟只适合测“服务端按 UA 分流内容”,不能用来复现内核差异导致的错误。

范围收敛为具体页面与错误类型的清单,根因仍需 DevTools 确认

三种前端报错采集方式的差异

这套按浏览器版本、页面 URL、错误堆栈三层下钻的做法,落到工具上通常有三条路:自己写 window.onerror 采集脚本、用浏览器自带的 DevTools 或性能面板、用第三方前端监控平台。三者在接入成本、去重口径、跨端统一、实时性和维护成本上的差别如下表。

对比维度自建JS监控脚本浏览器后台/性能面板前端监控平台
接入成本要自己挂 window.onerror 与 unhandledrejection,再写上报、接收端和存储DevTools 本地打开即可,零接入,但只反映你这台机器嵌一段监控 SDK,按文档配好上报地址即可,UA 自动解析成浏览器与版本
去重口径同一错误按 error.stack 算指纹的逻辑得自己写,指纹算漏了日志就刷屏面板按单条错误逐条列,不做跨用户聚类,刷不刷屏它不管同一错误按堆栈指纹自动聚合去重、合并计数,避免同一条报错刷屏(指纹与合并规则以产品文档/后台为准)
跨端统一Web、内嵌 H5、小程序的报错要分别采,浏览器与设备维度得自己归并只能看当前浏览器,拿不到版本与设备分布浏览器/版本/设备维度统一上报,错误堆栈可按浏览器和设备下钻(是否覆盖 App 内嵌 H5 以产品文档/后台为准)
实时性取决于自己的上报链路与存储,通常延迟几分钟到 T+1本地实时,但只对当前开发者可见控制台刷新频率(如分钟级)与可下钻时间范围以产品文档/后台为准,报错高峰当天可下钻
维护成本SDK 升级、UA 解析、sourcemap 还原、堆栈聚合与告警规则都要自己扛零维护,真实用户侧的报错分布它看不见堆栈聚合与采集由平台负责,告警规则可自行配置,sourcemap 还原仍由研发离线完成(以产品文档/后台为准)

常见追问

Q:window.onerror能捕获所有JS错误吗?

A:不能。它只能捕获同步执行中的错误。Promise未捕获的rejection需要监听unhandledrejection事件,资源加载错误需要在标签上监听error事件并设capture。

Q:线上JS错误怎么复现?

A:先看错误的浏览器版本和设备型号,在真实浏览器或远程设备上复现。Chrome DevTools的UA切换只改变请求头,不改变渲染引擎,不能用来复现浏览器兼容性问题。

Q:错误堆栈压缩了怎么办?

A:需要sourcemap。构建时生成sourcemap文件,部署时把sourcemap上传到监控平台,监控平台会自动把压缩后的堆栈映射回原始源码位置。具体支持情况以产品文档为准。

五、为什么选用456数据

四维下钻跑完一遍,你会发现能不能自动聚合错误堆栈才是工具分水岭。先按浏览器及版本切出异常簇、再按页面 URL 收敛、最后按堆栈指纹聚类,在控制台里分别对应按 UA 筛选、按页面聚合与堆栈指纹聚类——不用自己写采集脚本搭存储,切两下就能把“全站报错”收敛成“某个版本、某个页面、某类堆栈”的一小簇样本。其中各版本(免费版/基础版/专业版)具体开放哪些能力、是否覆盖 App 与小程序的前端监控,以产品官网与后台套餐说明为准。如果你们已经在用自建 JS 监控脚本,对比上面这张表的五项差异再决定;浏览器 DevTools 性能面板能覆盖的场景,也没有必要额外接一套监控。

你上次遇到“只有特定浏览器报错”是怎么定位的?是先看版本分布,还是先看堆栈聚类?欢迎在评论区说说你的排查路径。

相关阅读

周报周期和默认筛选怎么固定?看板配置的三步法_缩略图 周报周期和默认筛选怎么固定?看板配置的三步法 我做管理这些年,周一晨会的第一件事就是翻上周报表。这份报表跟着我搬过三次工位,口径也变过好几轮:最早是安排实习生手工拼Excel,后来换成在线表格共享,再后来才有了固定看板。回头看,晨会报表最大的成本不是做表,而是每周都在对口径。这篇文章把我踩过的坑归纳成三件要固定的事:统计周期、默认筛选、口径备注。这类固化思路,在多数看板工具里都是按“周期—筛选—备注”三段来组织的。周报口径演变时间线——从手工导表对口径,到共享表格忘切筛选,再到固定看板。一、一条口径混乱的时间线第一个阶段,大概十年前:每周五下午安排一个实习生,从各个后台系统分别导出CSV,再手工粘贴到固定Excel模板里,周一晨会前一晚才... 09 / 30·阅读 0 A/B测试主指标和观察窗口怎么定?四个设定前提_缩略图 A/B测试主指标和观察窗口怎么定?四个设定前提 带学员做实验设计练习时,我最常看到的一幕是:实验已经建好、一半流量也切出去了,团队却还在争论“到底看哪个数”。有人看点击率,有人看成交额,过两天又有人提出应该看次日留存,谁也说服不了谁。之所以会出现这种局面,是因为主指标、护栏指标和观察窗口这三件事没有在分流之前写清楚。这篇文章只解决一个问题:开实验之前,这三件事各自该怎么定。假设、主指标、护栏指标、观察窗口四栏都还是空白待填。一、为什么这三件事必须在开跑之前定实验一旦开始分流,用户就被随机分进对照组和实验组。这时候才回头挑指标,等于在同一批已产生的数据里挑一个“看起来赢了”的方向下结论,事后挑指标会让结论失去统计意义。判据必须先于数据存在:先... 09 / 30·阅读 0 资源失败率没涨但加载变慢?Resource Timing定位方法_缩略图 资源失败率没涨但加载变慢?Resource Timing定位方法 上周有个做电商的朋友约我喝咖啡,坐下没两句他就皱着眉问:“我们监控里资源失败率一直平着,一个告警都没报,可老板最近总说页面越来越慢,这到底是哪儿出了问题?”我反问他一句:你盯的是失败率,那你看过耗时趋势吗?他愣了一下——显然没有。这其实是个特别典型的错位。失败率和加载耗时,本来就是两件不相干的事:失败率统计“加载失败”的资源占比,耗时统计“加载成功、但花了多久”。一个资源每次都加载成功,只是从1秒慢慢变成3秒,失败率纹丝不动,用户却实实在在觉得页面变卡了。“监控没叫、老板却在叫”,往往是因为团队的告警只盯着失败率,没有人持续盯耗时趋势。一、失败率和耗时,为什么会错位我给他画了张图:左边是四周资... 09 / 30·阅读 0 标签重叠严重?互斥人群分群的三条规则_缩略图 标签重叠严重?互斥人群分群的三条规则 上周连着开了三个会:市场部要一个“潜客人群包”,运营部要一个“活跃用户包”,销售部要一个“高意向客户包”。三个包都从我这出,听起来不复杂。可等三个包的人数摆到一张表上,问题就来了——加起来8.2万人,我拿去重,真实去重后只有5.1万。也就是说,有3万多人同时躺在两三个包里,被三个部门反复触达,预算也被重复算了一遍。之所以会变成这样,不是哪个同事圈错了,而是从头到尾没人规定过“同一个人到底算谁的”。更直接的后果是,同一个客户一天能收到三条不同部门的推送,体验差到直接取关。一、重叠是怎么自然发生的把三个包的条件摊开看就明白原因了。市场圈“近30天访问过官网”,运营圈“近7天打开过App”,销售圈“... 09 / 30·阅读 0 RFM高价值人群怎么筛?分层阈值的三个判断维度_缩略图 RFM高价值人群怎么筛?分层阈值的三个判断维度 咨询现场最常被问的一句话是:“到底谁算我们的高价值用户?”有人主张按累计消费排,把花钱最多的那批挑出来;有人反驳说那些人只买过一次早就走了;还有人坚持看复购,天天回来的才是自己人。三方各执一词,吵到最后往往靠老板拍板。吵成这样不奇怪——“高价值”这三个字从来不是单一维度,把它拆成能算的三件事,争论才会停。一、先把“高价值”拆成三个可算的问题RFM不是什么高深模型,它就是把“高价值”拆成三个都能从订单里算出来的维度:R(Recency,最近一次消费):上一次下单离今天过去了多少天,越近越好;F(Frequency,消费频次):选定周期内这个人一共下过几单,越多越好;M(Monetary,消费金额... 09 / 30·阅读 0