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

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

周一早上九点十五分,我刚倒上咖啡,告警群就先炸了: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 性能面板能覆盖的场景,也没有必要额外接一套监控。

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

相关阅读

网站数据分析先看哪 3 个指标?别一上来铺 10 个看板 目录索引网站数据分析先看三个指标,不是十个三个指标怎么选:一个看量、一个看质、一个看钱三个指标一起看才有意义看板怎么砍到一屏什么时候才该加第四个指标这套在工具里怎么落地延伸阅读  网站数据分析不必一上来铺十个看板:先看三个指标,一个看量、一个看质、一个看钱,三个一起看才判断得出该改哪一步。▌网站数据分析先看三个指标,不是十个  新搭看板时最常见的做法是“能想到的都放上”:UV、PV、访问时长、跳出率、新访客率、渠道数、页面数、转化率、加购率、复购率,一屏十个。结果是谁都看,谁都不改。  问题不在指标本身,而在没有主次。十个指标里必然有几个动、几个不动,看完之后需要自己判断“哪几个重要”,判断成... 11 / 05·阅读 25 456数据技术岗位招聘:AI Agent、智能运维、数据采集与移动安全 目录索引岗位一:JavaAIAgent前端/后端开发工程师岗位二:AI智能运维工程师(AIOps/DevOps/SRE)岗位三:AI爬虫工程师/Android逆向安全工程师/iOS上架工程师投递方式  456数据技术团队正在扩编,本轮开放三个技术岗位,覆盖AIAgent研发、智能运维、数据采集与移动端安全三个方向。全部岗位支持远程,薪资18K–50K,按能力定级。岗位速览岗位重点考察工作地点薪资岗位一:JavaAIAgent前端/后端开发工程师高并发、大数据处理、Java/前端编码、AIAgent开发与交付远程/到场/海外居家18K–50K岗位二:AI智能运维工程师(AIOps/DevOps/... 11 / 04·阅读 33 用户行为追踪别只采集,从漏斗漏损最大那层下手 目录索引用户行为追踪别只采集,先看漏损在哪采集全集之前,先定三个问题漏损定位:从大到小,一层一层收追踪到动作,才算追到人追踪的边界:哪些不该追这套在工具里怎么落地常见问题延伸阅读  用户行为追踪最常见的失败是“采了全站、没人看报表”。有效的做法是先定位漏斗里漏损最大的那一层,只追那一层相关的动作,把属性补全,问题解决了再往下追。▌用户行为追踪别只采集,先看漏损在哪  打开埋点方案,经常能看到一张几十行的表:点击、滚动、悬停、复制、分享,全站能想到的动作都在里面。三个月后回头问一句“上周漏在哪一步”,没人答得上来。  原因很简单:采集解决的是“有没有”,追踪解决的是“为什么”。动作采得再多,如果... 11 / 04·阅读 24 网站转化分析卡在第一步:先把转化目标定清楚 目录索引网站转化分析做不下去,通常是目标没定转化目标怎么定:一句话、可计数、有责任人三类常见目标与它们的边界定完目标,先看漏损在哪一步转化目标和报表怎么对上这套在工具里怎么落地什么情况下先别做转化分析常见问题延伸阅读  网站转化分析做不下去,多半不是漏斗画错了,而是转化目标没定:目标不止一个,报表就只能并列摆着,谁也说不清哪一步该改。▌网站转化分析做不下去,通常是目标没定  打开工具先拉漏斗,是很多团队的习惯动作。三分钟画出一个五步漏斗,每一步都有数字,看上去很完整。然后问题来了:这个漏斗算的是注册、是下单、还是留资?三个都想算,于是并排放三张,半年后没人再看。  网站转化分析的第一步不是画漏... 11 / 04·阅读 20 「一套SDK多端统计」先别急着买,六类接入方式说清再定 目录索引「一套SDK多端统计」在工程上是两件事六类接入方式各管什么什么情况下真能一套搞定什么情况下必须分开接接入之后,怎么确认真的收到数了选工具时问哪四个问题档位与成本怎么算常见问题延伸阅读  「一套SDK多端统计」听起来省事,真正的限制在接入这一层:网站、小程序、App各有各的SDK,先把六类接入的边界弄清楚,再判断自己能不能一套搞定。▌「一套SDK多端统计」在工程上是两件事  「一套SDK多端统计」在销售嘴里是一句话,落到工程上是两件事:同一份代码能不能跑在多个端,和多个端的数据能不能进同一个后台。  第一件是接入问题,取决于各端的技术栈;第二件是数据问题,取决于后端怎么收、怎么去重。两件... 11 / 04·阅读 13