跳转至

会话重放采集原理与数据完整性

会话重放(Session Replay)用于还原用户在 Web 页面中的操作过程。它不是屏幕录像:浏览器 SDK 记录页面完整快照和后续变化,将数据压缩、分段上传;播放时,平台再根据这些数据重建页面。

理解这一点有助于区分三种现象:

  • 没有采集:未开始录制、未命中采样或浏览器能力不满足;
  • 采集链路发生缺口:页面变化超出保护预算、网络永久失败或页面突然关闭;
  • 数据已上传但视觉不完整:图片、字体或样式在播放时不可访问,或者内容受隐私规则和能力边界限制。

数据如何生成

初始化并开始录制
会话采样与录制资格判断
完整快照(页面基线)
DOM、输入、滚动、鼠标、样式、Canvas 等增量
压缩并生成有序分段
常规网络发送;离页时尝试 beacon / XHR
平台处理并生成可播放文件

1. 初始化和采样

SDK init() 完成后,还必须显式调用:

datafluxRum.startSessionReplayRecording()

调用前发生的页面状态和操作不会被倒推补录。录制是否真正开始,还取决于当前 Session 是否命中 sessionReplaySampleRatesessionReplayOnErrorSampleRate

使用:

datafluxRum.isRecording()

可以确认当前页面是否已经进入录制状态。

startSessionReplayRecording({ force: true }) 可强制当前 Session 具备回放资格。该选项会改变采样行为,建议仅在已明确需要强制录制的业务场景中使用。

2. 完整快照

录制开始时,SDK 会先生成一份可播放的页面基线,包括:

  • 当前页面地址和视口;
  • 焦点状态;
  • DOM 结构、属性、文本和滚动位置;
  • 浏览器支持时的 Visual Viewport 信息。

完整快照生成期间,如果页面 DOM 仍在快速变化,SDK 会放弃混合了不同时间状态的快照并重新构建。超大页面或持续高频变化的页面可能多次失败;连续恢复失败时,SDK 会停止当前页面的录制,避免继续生成无法正确播放的数据。

3. 增量记录

完整快照之后,SDK 持续记录:

  • DOM 节点新增、删除、文本和属性变化;
  • 鼠标、触摸、点击和滚动;
  • 输入框值变化;
  • 视口尺寸变化;
  • 音视频元素的播放、暂停和进度状态;
  • 样式规则变化;
  • 已开启的 Canvas 记录。

这些增量依赖此前的完整快照。例如,增量引用了节点 ID,但对应基线没有成功上传,播放端就无法正确应用这条变化。

4. 分段和上传

SDK 会把记录压缩为有序分段。正常录制时,分段通常每约 5 秒、接近内部大小目标、发生 View 切换或页面生命周期变化时刷新。

常规网络失败会按顺序进入内存重试队列。离线、HTTP 4084295xx 会重试;多数其他 4xx 属于不可重试错误,会使对应分段永久丢弃。

如果某个分段确定无法交付,SDK 会让依赖它的同一基线代次失效,并尝试生成新的完整快照。新快照成功后,后面的页面状态可以继续播放,但永久丢失分段覆盖的操作过程无法补回。

错误回放如何保留错误前数据

配置 sessionReplayOnErrorSampleRate 后,命中的 Session 会先在浏览器内存中保存锁定的回放分段。发生错误后,SDK 才会解锁并上传最近的页面基线和增量,并继续录制到 Session 结束。

它提供的是错误前最多约一分钟的上下文,而不是无限历史:

  • Session 没有发生错误时,锁定数据不会上传;
  • 页面在错误发生前关闭时,内存数据不会进入上传链路;
  • 内存缓存达到保护上限时,SDK 会从新的完整快照重新建立可播放基线。

因此,错误回放适合定位错误前操作,不适合替代普通回放保存所有无错误 Session。

DOM 数据什么时候可能缺失

浏览器 SDK 为避免会话重放长时间占用主线程,对序列化和缓存设置了保护边界。当前实现中,完整快照最多处理 20 万个节点,估算大小约为 4 MiB;DOM 树深度、单节点属性数、文本长度、样式规则和增量队列也都有边界。

以下场景可能触发截断、丢弃或重新建立基线:

  • 页面一次性创建或替换超大 DOM 子树;
  • 单个文本、属性或内联样式异常大;
  • 高频 DOM 更新持续时间过长,无法得到稳定快照;
  • Mutation 增量产生速度持续高于 SDK 的处理速度;
  • 页面同时包含大量 Shadow Root、样式规则和超大列表;
  • 浏览器读取 DOM 或 CSSOM 本身出现长时间阻塞。

SDK 不会发送半条结构变化。如果一个不可拆分的 DOM 变化过大,会丢弃整条变化并请求新完整快照。这样可以恢复后续页面的一致状态,但不能恢复缺口期间的每个中间步骤。

上述数值是当前 SDK 的内部保护阈值,不是可配置项,也不作为长期稳定的公开 API。排查时应以实际使用的 SDK 版本为准。

隐私规则导致的预期缺失

默认隐私级别为 mask-user-input。以下数据可能被遮罩、隐藏或替换为占位内容:

  • 密码、邮箱、电话、隐藏输入;
  • 信用卡自动填充相关字段;
  • 通过隐私属性或隐私类名标记的节点;
  • shouldMaskNode 返回需要屏蔽的自定义节点;
  • 脚本内容和被隐藏节点的子树。

这类内容缺失属于数据安全策略,不是网络丢包。排查“输入为空”或“某区域没有内容”时,应先检查隐私配置。

HTML 和 Shadow DOM 的能力边界

当前采集边界如下:

内容 采集情况
普通 DOM 支持
open Shadow DOM 支持可访问的结构、变化和相关样式
closed Shadow DOM 无法保证采集
Web Components 取决于 Shadow Root 是否开放,以及内部使用的内容类型
iframe 可记录 iframe 元素本身,不记录其内部文档用于完整还原
video / audio 可记录元素和播放状态,不采集媒体音轨或逐帧视频内容

Canvas 和 WebGL 为什么会掉帧

Canvas 录制默认关闭。必须满足以下条件:

  • Session Replay 已命中采样并正在录制;
  • replayCanvasEnabled: true
  • 目标 Canvas 已进入可采集的 DOM;
  • WebGL/WebGL2 场景已额外注册 WebGL Replay 插件。

Canvas 自动录制采用有预算的调度,不承诺逐帧采集。以下情况可能出现视觉帧缺口:

  • 动画速度高于采集节奏;
  • 页面隐藏,自动调度暂停;
  • 多个 Canvas 等待公平轮转或并发编码;
  • 画面未变化而进入退避;
  • Canvas 尺寸、编码结果或单次命令过大;
  • Canvas 尚未连接到 DOM,或其 DOM 基线尚未发布;
  • WebGL 插件在引擎创建 Context、缓存绘制方法之后才初始化;
  • 最后一次 WebGL 绘制发生在冷却或编码期间,之后没有新的绘制触发采集。

WebGL Replay 是由绘制驱动的受预算像素快照,不是 WebGL 命令级重放,也不是逐帧视频。详细配置与性能边界见如何接入 Canvas 录制

页面关闭时为什么容易丢失尾部

回放的编码结果和重试队列都只保存在浏览器内存中。页面隐藏、冻结或卸载时,SDK 会主动刷新待处理记录,并尝试通过 sendBeacon 或 XHR 交付。

退出阶段仍然存在以下限制:

  • 浏览器留给 JavaScript 的时间很短;
  • 退出阶段有有界的发送预算,待发送数据过多时尾部会被丢弃;
  • sendBeacon() 返回成功只表示浏览器接收了排队任务,不代表服务端已经持久化;
  • 强杀浏览器、浏览器崩溃、移动系统回收进程、断电或网络断开会直接清除内存队列;
  • 页面关闭前尚未解锁的错误回放数据不会上传。

不要把关键数据的可靠交付完全依赖于 beforeunload。尽早开始录制、让页面在关键操作后保留正常发送时间,比增加离页逻辑更有效。

数据已上传,为什么播放仍不完整

会话重放按 DOM 和资源地址重建页面,不会把所有图片、字体和外部样式完整打包到回放数据中。即使回放分段全部上传成功,仍可能因为以下原因显示异常:

  • 图片、字体或样式资源已下线或地址已变化;
  • 资源需要登录态、签名或内网访问;
  • CORS 不允许播放页面加载资源;
  • CSP 阻止 Worker、Blob URL 或资源加载;
  • 跨域样式表的 CSSOM 不可读取,只能在播放时重新请求原始链接;
  • 平台侧数据处理、索引或回放文件生成尚未完成或失败。

资源问题通常表现为 DOM 结构仍在,但字体、图片、布局或悬停样式不正确。

数据缺口分类

分类 常见原因 后续能否继续
未录制 未调用开始 API、未采样、浏览器不支持 成功开始后可记录,之前无法补回
开头缺失 SDK 初始化或开始录制过晚 后续可继续,开头无法补回
隐私遮罩 默认隐私规则或自定义屏蔽 属于预期行为,不应恢复原文
能力边界 closed Shadow DOM、iframe 内文档、媒体内容、Canvas 未开启 不支持的数据无法补回
DOM 保护边界 页面过大、持续抖动、增量队列溢出 新完整快照后可恢复一致,缺口过程无法补回
Canvas 调度边界 冷却、退避、隐藏页、编码或尺寸限制 后续快照可恢复当前画面,不保证中间帧
Worker/编码失败 CSP、Worker 创建失败、编码异常或持续背压 重新开始录制后可能恢复
网络永久失败 不可重试 4xx、内存队列满、代理拦截 新基线后可继续,旧分段无法补回
页面突然关闭 强杀、崩溃、系统回收、退出时间不足 尾部通常无法补回
资源加载失败 CORS、鉴权、资源过期或 CSP 修复资源可访问性后可能改善显示
平台处理异常 上传成功但处理或文件生成失败 取决于服务端处理结果

如何排查

建议按以下顺序检查:

  1. 录制资格:确认采样率、是否调用 startSessionReplayRecording(),并检查 isRecording()
  2. Session 和 View:执行 getInternalContext(),确认 Application ID、Session ID 和 View ID 存在且符合预期。
  3. 客户端请求:在浏览器开发者工具中过滤 /v1/write/rum/replay,记录请求时间、状态码、响应和失败原因。
  4. Worker 与安全策略:检查控制台中的 Worker、Blob URL、CSP 和 Canvas 编码错误。
  5. 隐私与能力边界:确认缺失区域是否属于遮罩、closed Shadow DOM、iframe、音视频或未开启的 Canvas。
  6. 资源可访问性:从回放环境验证图片、字体和 CSS URL 的有效期、鉴权、CORS 和 CSP。
  7. 平台处理状态:如果客户端请求成功但仍无数据,记录 Session ID、Application ID、发生时间、SDK 版本和请求响应后继续排查。

降低数据缺口的建议

  • 尽早初始化 SDK 并开始录制;
  • 根据业务量设置明确的普通回放和错误回放采样率;
  • 避免一次性写入超大 DOM 子树、文本、属性和内联样式;
  • 大型列表和高频页面状态分批更新;
  • 为图片、字体和 CSS 提供稳定地址,并正确配置 CORS 和 CSP;
  • 只在需要的页面开启 Canvas,根据场景选择手动、自动快照或高还原度模式;
  • 在 WebGL 引擎启动前初始化 WebGL Replay 插件;
  • 监控 /v1/write/rum/replay4xx4295xx 和网络失败;
  • 排查时保留 Session ID、View ID、SDK 版本、浏览器版本和页面生命周期信息。

更多阅读

文档评价

文档内容是否对您有帮助?