前端错误监控

共 32 题
📑 题目列表 32 题
#
★★★

1. Sentry 上报中的 beforeSend 钩子在脱敏敏感数据(PII、Token)的工程实践

在 Sentry 上报错误时,如何利用 beforeSend 钩子对 PII(如手机号、身份证号)与 Token 等敏感数据进行脱敏?脱敏应该覆盖哪些事件字段?

  • beforeSend 的调用时机与返回值语义
  • 敏感字段的识别策略与掩码方案
  • 脱敏与采样、过滤在事件处理链中的位置

beforeSend 是 Sentry 在事件发送到服务端之前执行的同步钩子,接收完整事件对象,返回修改后的事件则继续上报,返回 null 则丢弃该事件。脱敏工程通常在这里递归遍历事件对象的 request.headers、user、contexts、extra、tags、breadcrumbs 等字段,按键名正则(如 /(token|password|phone|idcard)/i)或值格式匹配敏感内容,替换为 **** 掩码或哈希值。由于前端事件一旦上传,服务端 DSN 通道内的数据便难以回退,因此脱敏必须前置到客户端钩子中完成。此外还应结合环境判断,在生产环境强制启用脱敏、开发环境保留完整上下文,并避免在 beforeSend 中执行耗时或异步逻辑,防止阻塞上报。

本题考察对错误上报生命周期钩子的理解。beforeSend 处于"事件已组装、尚未传输"的最后一环,是统一治理敏感数据的唯一可靠位置;回答时需点明返回 null 的双重用途(丢弃噪声与丢弃含密事件),并覆盖 PII 与 Token 两类典型的脱敏对象,体现生产环境的工程完备性。

Sentry.init({
  dsn: '...',
  beforeSend(event) {
    const MASK_KEYS = /(token|password|secret|phone|idcard|authorization)/i;
    const mask = (obj) => {
      if (!obj || typeof obj !== 'object') return;
      Object.keys(obj).forEach((k) => {
        if (MASK_KEYS.test(k)) obj[k] = '****';
        else if (typeof obj[k] === 'object') mask(obj[k]);
      });
    };
    mask(event.request);
    mask(event.contexts);
    mask(event.extra);
    return event;
  },
});
#
★★★

2. window.onerror/unhandledrejection/error 事件在前端错误埋点的工程取舍

window.onerror、unhandledrejection 与 addEventListener('error') 在捕获前端错误时分别覆盖哪些场景?工程上应如何取舍与组合?

  • 三类监听器捕获的错误类型差异
  • 捕获阶段与冒泡阶段对资源加载错误的影响
  • 与框架错误边界(ErrorBoundary)的配合层级

window.onerror(或捕获阶段的 error 事件监听)捕获全局未捕获的 JavaScript 运行错误,能拿到 message、source、lineno、colno 与 error 对象;addEventListener('error', fn, true) 使用捕获阶段,还能捕获资源加载失败(img、script 的 error 事件,但拿不到堆栈);unhandledrejection 则捕获未被处理的 Promise rejection,这是 onerror 覆盖不到的异步错误重灾区。工程取舍上,通常用 addEventListener('error', handler, true) 替代直接赋值 window.onerror,避免覆盖他人监听;同时分别监听 unhandledrejection 并统一序列化上报。框架内部错误(React 渲染错误)不会触发 window.onerror,需由 ErrorBoundary 捕获后手动上报,形成"全局兜底 + 框架边界 + 业务 try/catch"三层体系。

本题考察错误捕获机制的精确边界。关键得分点是区分"运行错误"与"资源错误"(前者有堆栈、后者无堆栈且仅在捕获阶段可拦截)、识别 Promise rejection 的独立事件通道,以及说明全局监听与框架错误边界的分工,避免把三者混为一谈。

#
★★★

3. Sentry 与 Rollbar/Bugsnag 在 Source Map 上传与错误分组能力的工程取舍

Sentry、Rollbar、Bugsnag 在 Source Map 上传流程与错误分组(grouping)能力上有哪些差异?选型时应如何取舍?

  • 三家平台的 Source Map 上传方式(CLI、插件、Sentry API)差异
  • 错误分组(fingerprint/grouping rules)的机制对比
  • 团队规模、自建成本与生态集成对选型的影响

三者均支持 Source Map 符号化,但工程细节不同:Sentry 提供 sentry-cli、@sentry/vite-plugin 等构建期插件,可把版本号(release)与提交(commit)自动关联,栈还原体验最顺滑;Rollbar 通过 deploy API 与构建钩子上传,强调部署上下文与版本追踪;Bugsnag 提供 @bugsnag/source-maps 与 CLI,支持通过 build 对象把版本与仓库提交绑定。错误分组方面,Sentry 基于堆栈与异常类型自动聚合,并提供 fingerprint、grouping-enhancements 深度定制;Rollbar 与 Bugsnag 也提供 fingerprint 与 grouping rules,但定制粒度与生态文档略逊。取舍时考虑:Sentry 生态与自托管能力最强、告警与追踪一体,适合监控体系化建设;Rollbar/Bugsnag 胜在简单与特定集成(如 Slack、Jira 原生联动),小团队或既有工具链契合度高时可优先。

本题考察监控平台选型的工程判断。回答要落到"Source Map 上传链路与版本关联"和"错误分组准确性"两个硬指标上,并补充部署形态(SaaS/自托管)与生态集成等决策维度,体现对工程成本的权衡而非单纯罗列功能。

#
★★★

4. 资源加载错误如何捕获(error 事件/资源 timing)并归因到网络/CDN/代码?

前端资源(JS、CSS、图片、字体)加载失败如何捕获?如何把失败归因到网络问题、CDN 故障还是代码路径错误?

  • 资源 error 事件捕获阶段监听的局限(无堆栈)
  • PerformanceResourceTiming 与 entryType 的诊断价值
  • 结合响应状态、重试次数与域名分组做根因归因

资源加载错误通过在捕获阶段监听 error 事件获取(element 的 target),但拿不到任何调用堆栈,只能得到元素与资源地址;要区分失败类型需结合 Resource Timing:检查 performance.getEntriesByType('resource') 中该资源的 duration、transferSize、initiatorType,若 duration 极长或响应为空则疑似网络超时,若 transferSize 为 0 则可能被 CSP/混合内容拦截或 CORS 读取限制。归因路径上:按域名聚合失败率(CDN 域名失败率突增 → CDN 故障)、按 URL 路径聚合(特定路径失败 → 构建产物问题)、按用户网络与地区聚合(特定运营商/地区失败 → 网络问题),再结合 navigator.onLine 与重试结果区分瞬时与持续失败。对关键资源(入口脚本)失败还应触发降级提示与自动重载,形成"捕获—归因—兜底"闭环。

本题考察资源监控的进阶能力。答题要点是承认 error 事件的先天不足(无堆栈、无法区分网络/代码),再用 PerformanceResourceTiming 与多维度聚合(域名、路径、地域、运营商)把失败归因到网络、CDN 或代码,展示数据驱动的排查方法。

#
★★★

5. Source Map 与版本关联的栈解析

Source Map 如何与发布版本(release/commit)关联以实现生产环境错误栈还原?关联机制失效时有哪些排查手段?

  • release 与 commit 的概念及在符号化中的作用
  • Source Map 上传时机(构建期)与读取时机(错误发生时)的匹配
  • 栈还原失败(版本不匹配、map 缺失)的排查路径

生产代码经过压缩混淆后堆栈不可读,Source Map 提供压缩代码到源码的行列映射。Sentry 等平台通过 release 标识(构建时注入到客户端 SDK,如 Sentry.init 的 release 选项)把上传的 Source Map 与线上错误绑定;进一步通过提交(commit)关联 Git 版本,让符号化后的栈能对应到具体代码版本。工程要点:必须在构建时同步上传与 release 匹配的 map 文件,且客户端 release 与上传版本必须一致,否则出现"找不到匹配的 Source Map";为此 CI 中常校验 release 值唯一、禁止 map 文件被浏览器直接访问(避免源码泄露)。排查还原失败时,先检查客户端 release 是否与上传一致,再用 sentry-cli 查询 release 关联的文件列表,确认 map 是否被覆盖、删除或未上传。

本题考察生产错误可调试性的关键链路。核心是"release 即契约":客户端注入、上传、查询三者必须使用同一标识;回答中同时点出版本漂移的常见原因(发布回滚、map 覆盖)与验证手段,体现对符号化机制的完整理解。

#
★★★

6. Sentry session-replay 与 RRWeb 的隐私保护工程价值

Sentry Session Replay(基于 rrweb)如何实现用户会话回放?在隐私保护上有哪些工程手段?

  • rrweb 录制 DOM 快照与增量事件的原理
  • 隐私遮罩(mask、ignore)的配置方式
  • 回放与错误/性能数据的关联分析价值

Session Replay 基于 rrweb 录制页面 DOM 快照(snapshot)与后续的增量事件(mutation、input、scroll 等),重建用户操作全过程。其工程价值在于把抽象的错误堆栈还原为可见的操作上下文:结合错误时间点回放,能直接看到报错前用户点击了什么、表单填了什么、界面处于什么状态,大幅缩短复现路径。隐私保护是回放落地的前提:通过 mask 配置把输入框、敏感选择器对应的内容替换为占位符(默认所有 input 被遮罩),用 block 配置隐藏整块区域(图片、图表),录制端还支持在回放中忽略指定元素;同时可设置采样率(如 10%)控制存储成本,并仅对登录态用户启用。还需注意回放数据与事件数据一样经过脱敏管线,避免把 PII 写入回放日志。

本题考察监控产品与隐私的平衡能力。答案需分两层:先讲清 rrweb 的快照+增量录制原理与回放对错误复现的价值,再强调 mask/block 遮罩、采样与存储策略等隐私工程手段,说明"录制能力越强、隐私责任越大"的工程边界。

#
★★★

7. 跨域脚本错误为何只能拿到 Script error,如何用 crossorigin 与封装绕过并保留堆栈?

为什么跨域脚本抛错时只能拿到 "Script error."?如何通过 crossorigin 属性与脚本封装保留完整错误堆栈?

  • 同源策略对错误信息的屏蔽机制
  • crossorigin 属性与 CORS 响应头的配合条件
  • 第三方脚本无法加 crossorigin 时的降级策略

浏览器基于同源策略屏蔽跨域脚本的详细错误信息,全局错误处理只能收到 "Script error." 而拿不到 message、堆栈与行列号,这是为了阻止恶意页面探测跨域资源内部实现。要拿到完整堆栈,需要脚本支持 CORS:给 script 标签添加 crossorigin="anonymous"(或 use-credentials),同时服务端返回 Access-Control-Allow-Origin 响应头,两者缺一不可,且 crossorigin 必须在脚本加载前设置。对于无法控制响应头的第三方脚本,可把其执行封装到同域代理或利用 Service Worker 拦截改写;更实用的是用动态加载 + 全局监听兜底:在脚本内包装 error 上报或通过 window 上的捕获监听接收其派生的自定义事件,部分场景还可借助资源 timing 判断其是否加载成功。生产上优先约束自有脚本统一走带 crossorigin 的 CDN,第三方脚本仅做加载失败与可用性监控。

本题考察同源策略在错误监控上的具体表现。核心逻辑链是"跨域 → 信息被屏蔽 → crossorigin+CORS 头 → 拿到堆栈";同时要给出不可控第三方脚本的替代方案(封装、降级、可用性监控),展示工程化的分级处理思路。

#
★★★

8. Sentry 的 source map 上传策略(CI 注入 @sentry/vite-plugin vs 后台上传)在生产栈追踪的工程取舍

Sentry Source Map 上传采用 CI 构建期注入 @sentry/vite-plugin 与构建后后台脚本上传两种策略,各有何优劣?如何取舍?

  • @sentry/vite-plugin 的自动关联 release 与删除 map 的能力
  • 后台上传的灵活性(跨构建工具、自定义清洗)与风险
  • 两种策略在生产栈追踪准确性上的差异

@sentry/vite-plugin 在构建结束时自动上传 map、注入 release 与 commit 关联,还能自动清理源文件目录中的 map 并配置 sourcemap 隐藏,整个流程对开发者透明、版本关联天然一致,是 Vite 项目的首选;缺点是绑定构建工具与网络条件——构建机必须能访问 Sentry,失败时可能导致发布阻断或静默降级。后台上传(sentry-cli 脚本/独立服务)不侵入构建,可对 map 做预处理(路径改写、多环境分流)、统一走私有网络代理,适合多构建链、离线构建或合规要求高(map 不出内网)的场景;风险是 release 映射可能滞后或配置漂移,造成某段时间栈还原失败。工程取舍上建议 CI 注入为主、后台批量上传为辅助,并把"栈还原成功率"纳入发布检查清单。

本题考察发布流水线与监控平台衔接的工程细节。得分点是理解两种路径的本质差异:构建期注入"版本即契约、自动一致",后台上传"解耦灵活、但需自管一致性";并结合发布阻断、内网合规等场景给出组合策略。

#
★★★

9. Source Map 与 X-SourceMap 头在 CDN 部署时的安全风险与替代方案

X-SourceMap 响应头在 CDN 部署 Source Map 时存在哪些安全风险?有哪些替代方案?

  • X-SourceMap 响应头的自动加载机制与暴露源码的风险
  • CDN 场景下 map 文件权限控制的难点
  • 替代方案:构建期上传、独立存储、鉴权访问

当浏览器开发者工具检测到响应头 X-SourceMap(或 HTML 中的 #sourceMappingURL 注释)时,会主动下载对应 map 文件用于还原源码。若 map 文件随构建产物一起部署到公开 CDN 且没有访问控制,任何人打开开发者工具都能获取完整源码,等于把压缩混淆的保护完全解除。此外 map 可能被搜索引擎与爬虫索引,形成持久泄露。替代方案的核心是"map 不出公开目录":首选构建期把 map 上传到监控平台(如 Sentry)并在产物目录删除文件;需要本地调试时,使用带鉴权的专用存储(签名 URL、内网访问)或仅开发/灰度环境输出 map;也可在构建时对 map 内容做路径改写或去 sourcesContent 后再加密,进一步降低泄露面。CDN 上如需保留,应配置禁止直接访问(如目录规则拒绝 .map 请求)并对 X-SourceMap 头做剥离。

本题考察源码保护与可调试性的平衡。核心认知是 map 与源码等价,公开 CDN 上的 map 等于公开源码;答题需给出"上传到平台 + 本地/受限环境调试 + 访问控制"的组合方案,展示安全工程素养。

#
★★★

10. React 的 ErrorBoundary 与 Vue 的 errorCaptured/app.config.errorHandler 在错误捕获的边界

React ErrorBoundary、Vue errorCaptured 与 app.config.errorHandler 在错误捕获的边界上有何差异?分别适合捕获哪些错误?

  • React ErrorBoundary 只能捕获渲染/生命周期错误的限制
  • Vue errorCaptured 的冒泡捕获语义与返回 false 的作用
  • 全局钩子与事件回调、异步错误的关系

React 的 ErrorBoundary(getDerivedStateFromError + componentDidCatch)只能捕获其子树在渲染、生命周期与构造函数中抛出的错误,无法捕获事件处理器、异步代码(setTimeout、Promise)、服务端渲染与自身抛出的错误,因此必须配合全局 window.onerror/unhandledrejection 兜底。Vue 的 errorCaptured 钩子从子组件向上冒泡传播,返回 false 可阻止继续向上传递,能捕获渲染、生命周期与事件回调中的错误;app.config.errorHandler 则是应用级最后兜底,捕获所有组件树未被处理的错误与生命周期错误,但同样无法覆盖原生异步回调与 Promise 中被 catch 的错误。工程实践:React 用 ErrorBoundary 做 UI 降级 + 全局监听做异步兜底;Vue 用 errorCaptured 做局部治理、app.config.errorHandler 做统一上报,两者都需要在框架层把捕获到的错误显式交给监控 SDK。

本题考察框架错误边界与全局监控的分工。核心差异在"同步渲染链路 vs 异步事件":框架边界只覆盖前者,后者必须依赖全局事件;同时注意 Vue 的冒泡语义(返回 false 阻断)与 React 的树状边界差异,避免答成二选一。

#
★★

11. try/catch 与 window.onerror 的边界——为何异步事件处理器内的错误需要全局兜底

try/catch 与 window.onerror 在错误捕获上有什么边界?为什么异步事件处理器内的错误需要全局兜底?

  • try/catch 只能捕获同步代码块的错误
  • 异步回调(setTimeout、Promise、事件)脱离词法作用域的错误传播
  • 全局监听作为异步错误兜底的必要性

try/catch 只能捕获同一执行栈内的同步错误;一旦代码进入 setTimeout 回调、事件监听器、Promise 链或异步函数体,错误发生在新的任务/微任务执行栈中,外层 try/catch 已经退出,无法捕获。window.onerror 与 unhandledrejection 恰好弥补这一缺口:前者兜住未捕获的同步与异步运行时错误,后者兜住未处理的 Promise rejection。因此工程规范是:业务代码用 try/catch 处理可预期的局部错误(如表单校验、文件解析),异步与第三方调用不假设 try/catch 覆盖,必须依赖全局监听做最后防线并统一上报;同时避免在全局处理器中抛错,防止监控自身被误报。async/await 语法会让 try/catch 覆盖 await 后的错误,但仍覆盖不到外层未捕获的 rejection,两者职责依旧不同。

本题考察执行栈与错误传播模型。答题关键是解释"try/catch 与调用栈绑定,异步回调换了执行栈",从而推出全局监听是异步错误的唯一可靠兜底;再给出 async/await 的局部改善与局限,体现对机制而非语法的理解。

#
★★

12. Service Worker 内的 self.addEventListener('error') 与 unhandledrejection 在离线缓存错误捕获的工程价值

Service Worker 内的 error 与 unhandledrejection 监听对离线缓存错误的捕获有什么工程价值?与页面侧监控如何打通?

  • Service Worker 独立于页面线程的错误场景
  • 缓存逻辑、fetch 拦截失败的典型错误
  • SW 内错误如何上报到监控平台

Service Worker 运行在独立的 worker 线程,其内部抛错(缓存 API 写入失败、fetch 拦截抛错、消息处理异常)不会冒泡到页面 window 的全局监听,需要单独注册 self.addEventListener('error') 与 self.addEventListener('unhandledrejection') 捕获。工程价值在于:缓存版本升级、离线缓存更新失败、预缓存清单与线上资源不一致等静默故障,恰恰发生在 SW 内部,若不监听将完全不可见。上报打通方式:SW 内通过 self.clients.matchAll() 找到受控页面并 postMessage 传递错误信息,由页面代理上报到 Sentry;或直接使用监控 SDK 的 SW 适配(如 @sentry/browser 的 service worker 支持)初始化最小实例直连上报端点。此外,SW 中的 fetch 拦截应始终 catch 后返回降级响应(如 Cache 兜底),并记录失败原因,形成"缓存命中率 + 兜底次数"的可观测指标。

本题考察多线程环境下的监控覆盖。要点是认识到 SW 线程的错误通道与页面隔离,必须自建监听与转发链路;同时把离线缓存这一典型故障域(版本切换、预缓存失败)纳入监控范围,体现对 PWA 运行机制的深入理解。

#
★★

13. Console.error 与上报系统的协作——开发环境 console 被禁用时上报系统的兜底

开发环境禁用 console 时,依赖 console.error 的错误上报为何失效?上报系统应如何兜底?

  • console 重写与禁用的常见手段及其副作用
  • 上报链路对 console 依赖的隐患
  • 独立于 console 的上报通道设计

许多项目会在生产或特定环境重写 console 以清理日志(如把 console.error 静默、覆盖 console 方法),若上报系统内部通过劫持 console.error 收集错误,或业务代码在 catch 后仅 console.error 而不显式上报,禁用 console 会让错误静默丢失。兜底策略:监控 SDK 不应依赖 console 通道,而是通过 window.onerror、unhandledrejection、fetch/XHR 拦截与框架钩子等独立通道采集;业务侧用统一上报封装(如 reportError(error))替代裸 console.error;对希望保留的开发体验,可在生产构建中仅禁用 console.log/debug,保留 console.error 并同时接入监控,或在上报封装内对 console 是否可用做防御性检测后降级到全局事件。规范上,console 只作为本地诊断出口,上报必须走显式链路。

本题考察监控通道的耦合与解耦。核心是识别"console 是可篡改的调试出口,不是可靠的数据通道",从而推出上报必须基于浏览器事件与 SDK 自建管道;再给出 console 分级禁用与防御性降级的具体做法。

#
★★

14. Sentry 的 Session Replay(基于 rrweb)

Sentry Session Replay 基于 rrweb 的实现原理是什么?其录制内容与回放分析有哪些工程要点?

  • rrweb 快照与增量事件的录制模型
  • 回放与错误/性能事件的关联机制
  • 采样、隐私与存储成本的权衡

Sentry Session Replay 基于 rrweb:页面加载时先记录完整 DOM 快照(含 CSS 状态),之后通过 MutationObserver 与事件监听持续记录增量(DOM 变化、输入、滚动、鼠标轨迹等),压缩后按时间序列存储,回放时按时间戳重建 DOM 并驱动事件,呈现用户真实操作。工程要点:回放与错误事件共用时间轴,报错瞬间可一键跳转回放,定位"错误前的操作路径";性能指标(LCP/INP)也可与回放叠加分析卡顿时的界面状态。落地时要配置采样率(如全量 5%~10%、错误时 100% 关联录制)、设置 mask/block 遮罩保护输入与敏感区域,并评估带宽与存储成本——录制的 DOM 变更事件量与页面动态性成正比,动态图表多的页面成本显著更高。

本题考察回放类监控的实现与成本模型。得分点在于讲清"快照+增量"而非录屏的原理差异、回放与错误/性能事件的时间轴关联价值,以及采样与隐私成本的三方权衡。

#
★★

15. Source Map 的 #sourceMappingURL 与 Performance 监控在调试生产错误的边界

#sourceMappingURL 与 Performance 监控在生产错误调试中各解决什么问题?二者的边界在哪里?

  • sourceMappingURL 的符号化作用与访问风险
  • Performance 数据(资源 timing、长任务)的定位作用
  • 调试链路中"堆栈还原"与"现场还原"的分工

#sourceMappingURL 解决"错误在哪一行源码":浏览器或监控平台据其找到 map 文件,把压缩堆栈还原为源码行列,属于错误符号化层。Performance 监控解决"发生了什么":资源 timing 揭示加载耗时与失败、Long Tasks/LoAF 揭示主线程卡顿、Web Vitals 揭示体验劣化,属于运行现场层。边界在于:Source Map 只回答"哪个函数、哪一行"(静态映射),回答不了"为什么此时失败"(动态上下文);Performance 恰好补充网络、渲染、交互等现场数据。工程上两者配合形成完整调试链:错误事件携带堆栈 + release 关联 map 还原代码位置,同时关联 performance entry 与时间线回放还原现场,从而在"代码缺陷、资源异常、性能超时"三类根因中做出区分。

本题考察监控体系的分层认知。答题需明确符号化(Source Map)与现场还原(Performance)是两个正交维度,错误排查必须双轨并行,避免把性能指标误当错误堆栈的替代品。

#
★★

16. 错误聚合(@sentry/grouping-enhancements)的 fingerprint 在堆栈相似的工程价值

Sentry 的错误聚合与 fingerprint 机制如何工作?@sentry/grouping-enhancements 在堆栈相似场景下有什么工程价值?

  • 默认分组规则(堆栈、异常类型)与 fingerprint 的优先级
  • 堆栈相似但根因不同时的误聚合问题
  • grouping-enhancements 的自定义分组增强实践

Sentry 默认按异常类型与堆栈帧聚合错误,但生产环境常见"堆栈相似、根因不同"(如同一个调用点被不同数据触发、压缩后堆栈过于雷同),导致误聚合、告警失真。fingerprint 是最高优先级的自定义分组键:在 beforeSend 或 SDK 配置中根据业务字段(错误码、接口路径、用户状态)计算哈希,把同类问题归并或把相似问题拆开。@sentry/grouping-enhancements 提供更精细的规则能力:按帧函数名、模块、异常信息正则等条件改写分组指纹,例如把第三方 SDK 内部帧从分组中剔除,或对特定错误码强制独立分组。工程价值:提升 issue 的"根因纯度",让告警数量与开发排障工作量线性对应,避免海量相似堆栈淹没真实高频故障。

本题考察监控聚合质量的工程控制。核心是理解"堆栈相似 ≠ 根因相同",fingerprint 与 grouping-enhancements 提供了从数据层干预聚合的手段;答题时给出误聚合的典型场景与自定义分组的具体做法即可体现深度。

#
★★

17. Sentry 与 OpenTelemetry 的事件关联(traceId/spanId)

Sentry 错误事件如何与 OpenTelemetry 的 traceId/spanId 关联?关联后的诊断价值是什么?

  • traceId/spanId 注入错误事件的机制
  • 前端 trace 与后端链路打通的意义
  • 事件关联在跨端根因定位中的价值

关联的核心是把分布式追踪上下文注入错误事件:前端初始化 OpenTelemetry(如 @opentelemetry/instrumentation-document-load、fetch 拦截)后,每次请求都会生成 traceId/spanId;Sentry 通过集成(sentry-opentelemetry 或 SDK 的 tracing 集成)读取当前 active span 上下文,把它写入错误事件的 contexts.trace,实现错误与追踪数据互跳。诊断价值在于:一个前端报错不再孤立,可以沿 traceId 串联该用户请求经过的页面、fetch 调用、服务端各服务与数据库 span,直接判断"错误是前端代码引起,还是上游 API 慢/错导致的连锁反应";同时 Sentry 内错误、性能事务、回放共享同一 trace,可一键从错误跳到性能瀑布与调用链。工程上需保证 trace 传播头(W3C traceparent)在 fetch/XHR 中自动注入,并统一 traceId 采样策略,否则关联率会大幅下降。

本题考察可观测性三大支柱(日志、指标、追踪)的前端落地。答题核心是"错误事件携带 trace 上下文、前端 trace 向后端传播"这一链路,以及关联后"错误→请求→服务"的跨层根因定位价值,体现对可观测性闭环的理解。

#
★★

18. 浏览器 ErrorEvent 与自定义 Error 类(继承 Error)在堆栈信息保留的边界

浏览器 ErrorEvent 与自定义 Error 类(继承 Error)在堆栈信息保留上有什么边界?监控上报时应如何取舍?

  • ErrorEvent 的字段结构与堆栈来源
  • 自定义 Error 类继承 Error 与丢失堆栈的坑(message 属性、name)
  • 序列化与传输对堆栈完整性的影响

ErrorEvent 是 error 事件的对象形态,包含 message、filename、lineno、colno 与 error 属性,其中 error 对象(如 TypeError 实例)携带完整堆栈,但资源错误(img/script 的 error 事件)没有 error 对象与堆栈。自定义 Error 类必须显式继承 Error(class BizError extends Error)并调用 super(message),否则 instance.name/message 与堆栈捕获会异常——堆栈在 new 时通过 Error.captureStackTrace 或 V8 的 Error 构造器生成,不调用 super 或手动设置 name 不更新堆栈首行;另外把 Error 实例直接放入 JSON 序列化会丢失 message/stack,需显式提取 { name, message, stack, cause }。监控边界:上报时应同时携带事件级字段(filename/lineno)与 error 对象级堆栈,对资源错误补充 resource timing 归因,并保证序列化器完整保留 stack 与 cause 链。

本题考察错误对象模型的底层细节。得分点是自定义 Error 的继承与 super 调用对堆栈的影响、JSON 序列化丢 stack 的坑,以及 ErrorEvent 字段与 error 对象堆栈的分层关系,这些是手写错误上报 SDK 的必备认知。

#
★★

19. 前端脚本错误(Script Error)跨域(crossorigin script)

什么是 "Script error."?跨域脚本错误在什么条件下能拿到完整信息,工程上如何处置第三方跨域脚本?

  • 同源策略对错误信息的屏蔽规则
  • crossorigin 属性与服务端 CORS 头的配合
  • 第三方脚本的兜底与降级策略

当脚本与页面不同源且未开启 CORS 时,浏览器只向全局错误监听暴露统一消息 "Script error.",隐藏真实 message、堆栈与行列号,这是同源策略的一部分。要解除屏蔽需同时满足两个条件:script 标签添加 crossorigin="anonymous"(或 use-credentials),且脚本响应携带 Access-Control-Allow-Origin 头。工程处置分两类:自有脚本统一加 crossorigin 并让 CDN 配置 CORS 头;第三方脚本(广告、统计 SDK)无法控制其响应头时,可放弃完整堆栈,退而监控其加载是否成功(resource timing/error 事件)、是否超时,以及通过封装代理(同域转发)或包装其内部回调获取部分上下文;对严重影响功能的三方脚本还可做动态降级(重试、替换 CDN 域名)。核心原则:跨域脚本错误信息获取以"受控脚本全量、三方脚本降级"为边界。

本题考察错误监控中跨域场景的处置体系。答题需先讲机制(同源策略屏蔽 + crossorigin/CORS 双条件),再给分层策略(自有全量、三方降级),体现既有原理又有工程边界控制。

#
★★

20. PWA Service Worker 缓存版本切换失败的 ErrorBoundary 与卸载策略

PWA Service Worker 缓存版本切换失败时,页面如何用 ErrorBoundary 兜底?SW 卸载与回滚策略如何设计?

  • 缓存版本切换失败的表现(旧缓存错配、预缓存失败)
  • 页面侧 ErrorBoundary 与版本信号的处理
  • SW 卸载(skipWaiting、unregister)与回滚策略

缓存版本切换失败常见两类:新版本预缓存清单与线上资源不一致导致 fetch 拦截返回损坏内容;新 SW 激活后页面仍运行旧代码引用已不存在的缓存。页面侧治理:用 ErrorBoundary 包裹根组件,捕获渲染期错误后展示"刷新/重试"降级 UI,并检测版本信号(如 window.APP_VERSION 与新版本不符)触发整页刷新或提示用户重载;对资源加载失败可在全局 error 监听中计数,连续失败时强制 bypass 缓存策略(fetch 直接走网络)。SW 侧策略:使用 skipWaiting + clients.claim 加速接管但保留回滚通道——把新旧缓存版本并存(cache 命名带版本号),新版本预缓存失败时保留旧缓存并终止切换;提供 unregister 兜底,当线上版本信息缺失或多次切换异常时注销 SW 回到网络模式,避免用户被"坏缓存"卡死。

本题考察 PWA 离线升级的故障面。答题需双线推进:页面侧用 ErrorBoundary+版本信号降级与刷新,SW 侧用版本化缓存并存、失败终止切换与 unregister 回滚,形成"升级失败可感知、可恢复"的闭环。

#
★★

21. error.cause(ES2022)在链式错误传递与现代监控的工程价值

error.cause(ES2022)如何实现链式错误传递?它对现代错误监控有什么工程价值?

  • error.cause 的语法与构造方式
  • 保留根因堆栈 vs 包装错误的取舍
  • 监控平台展示 cause 链与根因归集的能力

error.cause 允许在 new Error(message, { cause }) 时挂载底层错误,形成"外层业务错误 → 内层底层错误"的因果链,替代了以往把原始错误塞进 message 或附加自定义字段的做法。工程价值:服务层 catch 到网络/解析错误后,可抛出带 cause 的业务错误,既保留了业务语义(如"订单创建失败"),又完整保留了底层堆栈(网络失败发生在哪个请求、哪一行),排查时不再丢失根因。现代监控平台(Sentry 等)已支持渲染 cause 链(exception.values 多级展示),并可按根因(最内层异常)聚合分组,让不同入口的同类底层故障归并到同一 issue。实践要点:统一错误包装工具函数、序列化时显式携带 cause(JSON 不自动序列化 Error 的 cause 需手动提取)、避免多层包装导致链过长,必要时裁剪至 3~5 层。

本题考察现代错误模型对监控的赋能。答题核心是 cause 链让"业务语义与根因堆栈"兼得,以及监控端按根因聚合的价值;同时点出序列化与链长度等落地细节,体现对 ES2022 新特性的工程化理解。

#
★★

22. try/catch 中 caught error 在 Sentry 上报时丢失原始堆栈信息的 workaround

try/catch 捕获的错误在 Sentry 上报时为什么会丢失原始堆栈?有哪些 workaround?

  • 捕获后堆栈被替换或截断的原因(重新 throw、包装、异步边界)
  • 保留原始 error 对象的正确姿势
  • Sentry 侧分组与堆栈处理的配合

丢失堆栈的常见原因:catch (e) 后手动 new Error(message) 重新抛出(只保留新堆栈,旧堆栈丢失);把 e 序列化后仅传 message 字段;异步边界(回调/定时器)中重新抛出导致堆栈从当前调用点起算;以及某些框架把错误包装成普通对象。workaround 原则是"始终传递原始 error 对象":catch 后要么直接 throw e 交给全局监听,要么用 new Error(msg, { cause: e }) 挂载原对象、或调用 Sentry.captureException(e) 时直接传入原始 e;如需补充上下文,用 Sentry 的 setContext/setExtra 而不要改写错误本身;对必须跨异步传递的场景,先同步保存 error 引用再在新上下文上报。Sentry 侧配合:确认不启用会折叠堆栈的选项、按 cause 链分组以保留根因信息。

本题考察错误上报的实操细节。得分点是识别"重新 throw 新 Error、只传 message、异步边界"三类丢栈原因,并掌握"传原始对象 + cause 挂载 + captureException 直传"的 workaround,属于生产排障高频经验。

#
★★

23. ErrorBoundary 边界外的全局错误订阅(useEffect + subscribe)在第三方 SDK 错误的捕获

如何在 ErrorBoundary 边界外通过 useEffect + subscribe 订阅全局错误,捕获第三方 SDK 错误?边界在哪里?

  • ErrorBoundary 无法覆盖第三方 SDK 异步错误的局限
  • useEffect 中订阅全局事件与清理的写法
  • 第三方 SDK 错误的归属、去重与噪声控制

第三方 SDK 的错误常发生在事件回调、定时器、iframe 等 ErrorBoundary 不可及的异步上下文,需要全局订阅兜底。典型做法:在应用根组件 useEffect 中 addEventListener('error'/'unhandledrejection', handler),回调中过滤出第三方 SDK 的错误(按堆栈首帧或 source 域名归属),统一 Sentry.captureException 上报,并在 cleanup 中移除监听,避免重复订阅与泄漏。边界与注意点:订阅与 React 生命周期无关(事件在全局触发),所以 handler 内避免依赖过期闭包,需要外部状态时用 ref;对 SDK 错误按 SDK 名+错误类型分组去重、设告警阈值,防止三方广告脚本的错误淹没自有错误;同时与 ErrorBoundary 分工——边界内错误由组件降级处理,边界外由订阅兜底,两者都需显式上报才能覆盖完整。

本题考察"框架边界 + 全局订阅"的组合监控模式。答题要点是 useEffect 订阅的清理语义、错误归属与去重降噪,以及边界内外分工,体现对监控覆盖矩阵的完整设计。

#
★★

24. Frontend Error Monitoring 与 APM 后端追踪(OpenTelemetry/zipkin)

前端错误监控与后端 APM 追踪(OpenTelemetry/Zipkin)如何协同?trace 打通的关键点是什么?

  • 前端错误事件注入 trace 上下文的机制
  • W3C traceparent 与 B3 传播头的兼容
  • 前后端数据关联后的根因定位流程

协同的关键是"同一条 trace 贯穿前后端":前端初始化 OpenTelemetry(document-load、XMLHttpRequest/fetch 拦截等 instrumentation),为每个请求生成 traceId/spanId,并通过 W3C traceparent(或兼容的 B3)头随请求传递给后端;后端 Zipkin/OpenTelemetry Collector 接收后延续同一 trace。前端错误上报时把当前 active traceId/spanId 写入事件上下文,监控平台(Sentry 等)就能把错误与后端调用链关联:点击错误即可看到该用户请求从浏览器到网关、服务、数据库的完整 span 瀑布,快速区分错误根因在前端代码、网络、还是服务端。工程要点:统一传播头格式(W3C traceparent 为现代标准,zipkin 需 B3 兼容适配)、前后端采样率一致(否则一方丢弃导致 trace 断裂)、错误上报需同步携带 trace 且上报通道本身不能污染 trace。

本题考察可观测性链路的端到端设计。核心是 trace 上下文的前端生成、跨进程传播(traceparent/B3)与错误事件注入三位一体,以及采样一致性对关联率的决定性影响。

#
★★

25. Sentry 的 BrowserTracing 与 Web Vitals 联动的 INP/LCP 慢操作的根因定位

Sentry BrowserTracing 与 Web Vitals 如何联动定位 INP/LCP 慢操作的根因?诊断路径是怎样的?

  • BrowserTracing 生成性能事务与 span 的机制
  • INP/LCP 指标与 span 瀑布的关联
  • 慢操作的根因分类(主线程、网络、渲染)

BrowserTracing 通过 PerformanceObserver 采集 LCP、INP、CLS 等 Web Vitals,并把页面加载与交互过程建模为事务(transaction)与 span:LCP 对应 resource、paint、long task 等 span,INP 对应交互事件发生到下一帧呈现的输入延迟链路。联动定位时,平台按指标分位值(如 p75 LCP 超标)列出慢样本,点击样本进入瀑布:LCP 慢可看 TTFB→资源下载→图片解码→渲染 span,判断瓶颈在网络、图片体积还是主线程;INP 慢可拆分 input delay(事件回调长任务)、processing(处理器执行)、presentation delay(渲染被阻塞),配合 Long Task span 定位具体函数。工程上需开启 BrowserTracing 的 tracingOrigins 覆盖关键 API、配置合适的 sampleRate,并让 Web Vitals 与后端 trace 关联,才能从"指标慢"深入到"哪段代码慢"。

本题考察性能监控的产品化分析能力。答题要点是事务/span 模型如何把核心指标拆解为可定位的瀑布,以及 LCP/INP 各自瓶颈维度的拆分方法,展示从指标到根因的完整分析路径。

#
★★

26. 错误监控与告警策略(PagerDuty/Slack Webhook)

错误监控如何与 PagerDuty/Slack Webhook 集成做告警?告警策略设计有哪些要点?

  • 监控平台到通知渠道的集成方式(webhook、规则触发)
  • 告警分级的阈值与抑制策略
  • 避免告警疲劳:聚合、静默、escalation

集成方式:监控平台(Sentry 等)基于规则(新增 issue、错误量突增、特定 tag/环境匹配)触发 alert,通过内置集成或通用 Webhook 把告警负载推送到 PagerDuty(接入 incident 与值班 escalation)、Slack(消息到频道并带 issue 链接)。策略设计要点:分级告警——P0 阻断线上主流程的错误走 PagerDuty 电话/短信并 24h escalation,P2/P3 仅发 Slack 汇总;基于基线的动态阈值(如错误率相对过去 7 天基线上涨 3 倍)替代固定数量,减少误报;对已知问题、灰度环境、第三方 SDK 噪声做抑制与静默,按 release 关联告警归属到负责人;再配合 issue 去重聚合,让"一次修复对应一条告警"。还需设计恢复通知(issue 状态 resolved 后自动关闭告警)与告警复盘(周报聚合 Top 错误),避免告警疲劳。

本题考察监控闭环的运营设计。得分点是分级与动态阈值、抑制与静默、恢复通知三块,展示"告警数量可控、责任可追溯、升级有路径"的工程化告警体系,而非简单"接个 webhook"。

#

27. Promise.reject 未捕获与 unhandledrejection 的浏览器兼容性差异与监控兜底

未捕获的 Promise.reject 在浏览器中如何触发 unhandledrejection?不同浏览器的兼容差异如何影响监控兜底?

  • unhandledrejection 事件语义与触发时机
  • 浏览器对 rejection 处理的差异(事件、日志、顺序)
  • 监控侧的处理策略(捕获、去重、重抛)

当 Promise 被 reject 且没有调用 catch 时,浏览器在微任务队列清空后触发 window 的 unhandledrejection 事件(若再次为同一 promise 补上 catch 则触发 rejectionhandled 取消未处理状态),事件提供 promise 与 reason 字段。兼容差异:现代浏览器(Chrome、Edge、Firefox、Safari 新版)均支持该事件,但 Safari 旧版本支持较晚且行为有差异(如对已处理的 rejection 也可能报日志);不同浏览器的默认行为不同(Chrome 打控制台警告、Firefox 类似),且事件对象字段(reason、promise)在个别实现上可能缺失。监控兜底策略:统一监听 unhandledrejection 并把 reason(可能为任意值,需提取 message/stack)序列化上报;同时用 rejectionhandled 配合避免重复上报;对兼容性缺口,可在业务侧约定"所有异步函数显式 .catch 或 try/await",把对浏览器事件的支持当作最后防线而非唯一依赖。

本题考察 Promise 错误模型的兼容性认知。答题要点是 unhandledrejection 的触发时机与字段、跨浏览器差异的真实存在性,以及"事件兜底 + 业务显式处理"的双保险思路。

#

28. 网络错误(fetch abort/timeout)vs 业务错误(API 返回 4xx/5xx)

前端网络错误(fetch abort/timeout)与业务错误(API 返回 4xx/5xx)有何区别?监控上如何区分与分级处理?

  • fetch 网络层失败与 HTTP 状态码错误的语义差异
  • abort(AbortController)与 timeout 的识别
  • 错误分类对告警与重试策略的影响

网络错误发生在 HTTP 响应建立之前:fetch reject(TypeError: Failed to fetch)、超时(AbortController 超时触发 abort)、CORS 失败、网络断开等,属于"请求根本没到或没回";业务错误则是请求成功返回但状态码指示失败(4xx 客户端问题、5xx 服务端问题),或状态码 2xx 但业务体 code 非 0。监控区分:按 error.name(AbortError)、error.message、response.status、业务 code 字段分类,分别打标签 network_error / http_4xx / http_5xx / business_error。分级处理:网络错误可自动重试(幂等接口)、降级提示,5xx 关注服务端稳定性并告警,4xx 关注客户端代码与数据问题,业务错误按业务影响告警;上报时保留 method/url/status/耗时,便于定位是单点网络抖动还是全局故障。

本题考察错误分类学的基础。答题核心是把"传输层失败"与"应用层失败"分开建模,并给出按类型差异化的重试、告警与上报字段设计,体现对错误语义的精确区分。

#

29. Source Map 在生产环境的部署策略与访问控制,如何在可调试性与安全性之间取舍

Source Map 在生产环境如何部署与做访问控制?可调试性与安全性如何取舍?

  • map 文件泄露源码的风险模型
  • 访问控制手段(内网、鉴权、签名 URL)
  • 分级部署策略(灰度、按用户、按环境)

取舍的本质是"谁需要调试"与"谁能拿到源码"的矛盾。安全方案:map 不随静态资源公开部署,构建期上传到监控平台(Sentry/Rollbar)后从产物目录删除,线上栈还原完全由平台完成,浏览器无法下载——这是安全性最高且不损失监控调试能力的方式。需要浏览器端直接调试的场景(如支持用户自助反馈、内网工具),可对 map 做访问控制:部署在内网或带鉴权(token、签名 URL、同源 Cookie)的独立域,配置 CDN 拒绝公开访问 .map 路径、禁用 X-SourceMap 头,或仅在灰度/内测版本附带 map 而正式版剥离。技术兜底:即使 map 暴露,也建议构建时去除 sourcesContent(仅保留文件路径与映射)以降低源码完整泄露风险。核心原则:默认"map 不上公网",调试能力交给平台,安全与可调试性由此兼得。

本题考察安全与工程效率的平衡决策。答题核心是"监控平台符号化替代公网 map"这一模式,再辅以鉴权、去 sourcesContent、环境分级等纵深手段,体现对源码资产保护的成熟认知。

#

30. 微前端错误冒泡策略,子应用未捕获异常如何选择性上报并归属到对应应用/版本

微前端架构中子应用未捕获异常如何选择性上报?如何归属到对应的应用与版本?

  • 微前端主应用与子应用错误事件的隔离与捕获
  • 错误归属(应用名、版本、基座路由)的上下文注入
  • 选择性上报(过滤噪声、按应用策略)的实现

微前端中错误冒泡链路特殊:子应用(qiankun/Module Federation 等)运行在各自的沙箱或独立 bundle 中,错误可能被基座统一捕获,也可能在子应用内被拦截,归属易混淆。策略设计:子应用初始化时把自己的监控 SDK 实例(或基座统一 SDK 的 scope 上下文)绑定 release/应用名/版本/基座路由等信息,捕获异常时通过上下文标记归属;基座侧统一监听全局 error/unhandledrejection,根据堆栈中的子应用标识(如 webpack chunk 名、sourceURL、加载的 URL 前缀)做归属推断,无法归属的归为基座错误。选择性上报:按应用配置采样率与告警阈值,过滤第三方脚本与沙箱模拟产生的噪声(如 qiankun 的 Proxy 警告),子应用内部错误优先由子应用 SDK 直报(保留其 release 符号化),避免基座重复上报,可用事件去重键(错误消息+堆栈首帧+应用标识)合并。

本题考察微前端特有的监控归属问题。得分点是"上下文注入(应用/版本)"与"堆栈归因"双通道确定归属,以及采样、去重、过滤噪声的选择性上报设计,体现对多应用监控治理的理解。

#

31. 针对第三方脚本(如广告 SDK)抛错的隔离上报与告警降噪

第三方脚本(广告 SDK 等)抛错如何隔离上报?告警降噪有哪些手段?

  • 第三方错误识别(域名、堆栈首帧、chunk 名)
  • 隔离通道与独立分组、独立阈值
  • 降噪手段:静默、聚合、单独报表

第三方脚本错误(广告、统计、聊天 SDK)高频且不可控,若与自有错误混在一起会严重污染告警。隔离手段:按脚本域名、堆栈首帧文件名、window 上的 SDK 全局对象识别来源,在全局监听中分流——第三方错误进入独立事件流,打 third_party 标签并记录 SDK 名;上报时使用独立 fingerprint 分组或独立 project,避免与自有错误聚合。降噪手段:第三方错误不参与 P0 告警,只进周报或单独看板;设置更高的告警阈值(如错误率 > 30% 才告警)或按时间聚合(每小时合并);对已知的持续噪声(如特定广告位被 AdBlock 拦截导致的加载失败)直接静默并注明原因;同时监控其"是否导致页面功能故障"(如主 JS 未执行、白屏率),把监控重点从错误数量转向业务影响。

本题考察监控噪声治理。答题核心是"识别(来源归因)→ 隔离(独立通道与分组)→ 降噪(阈值、聚合、静默)+ 影响面监控",体现从错误计数转向业务影响的监控理念。

#

32. 如何确保上报通道本身不会因该异常导致递归失败

如何确保错误上报通道本身不会因上报过程抛错而递归失败或死循环?

  • 上报处理器内抛错的递归风险(监听器自触发)
  • 防护手段:try/catch、去重标记、节流
  • 上报失败时的降级与静默策略

递归失败的典型路径:全局 error 监听器内部抛错 → 该错误再次触发全局监听 → 监听器再次抛错,形成无限递归;或上报请求失败被自身捕获后再次上报,导致请求风暴。防护手段:全局处理器最外层用 try/catch 包裹并标记处理中(window.__handlingError 标志)或在开头检测当前错误是否已被处理过,同一错误只处理一次;对上报动作做节流与队列(批量、限速、上限),失败后指数退避重试而非立即重发;上报通道(fetch/beacon 发送)独立封装,其自身异常只 console 记录或进入内存环形缓冲,绝不回到全局错误流;还要防止"上报的错误被监控 SDK 自身监听器捕获后再次上报"的循环,用堆栈首帧或事件 id 判重。最后,监控不可用时应静默降级(丢弃或本地缓存限时重试),保证监控组件故障不影响业务。

本题考察监控系统自身的稳定性设计(自举保护)。答题核心是"递归入口阻断 + 上报通道隔离 + 节流退避 + 静默降级"四层防护,体现对监控可用性的元认知。