ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

录制回放优化:解决JSON体积、卡顿与安全三座大山

2026/9/3 2:24:40 拓冰建站 浏览量
录制回放优化:解决JSON体积、卡顿与安全三座大山 这类录制回放方案我见过太多次功能demo跑得挺顺一接入真实用户环境立刻暴露三个问题——录制日志体积爆炸、回放卡顿严重、敏感信息明文落地。这三个问题往往是同时出现的而且根因都指向同一个设计决策把“录制用户操作”简单理解成“把每个事件记录成JSON存下来”。本文就围绕“JSON 比视频还大”“回放卡成幻灯片”“用户密码直接展示在快照里”这三个具体问题从数据生成、存储、渲染、安全四个角度拆一遍并给出一套可以照着落地的优化顺序。先说结论这类方案不是不能用而是要做三层改造。第一层是数据要把无脑的每事件明细改成带快照策略和压缩策略的结构化日志。第二层是渲染要用分帧调度替代“一次性塞给浏览器”。第三层是安全要在录制入口就按字段级别做脱敏而不是等到展示端再补救。下面按实际落地顺序拆开讲。1. 先搞清楚录制回放的数据到底是怎么长胖的很多人一看到 JSON 文件比视频还大第一反应是“压缩没做”。实际上压缩只能把体积减少一部分真正的问题是存储内容的数据模型本身就在无限膨胀。录制回放的本质是记录“用户行为”不是记录“屏幕画面”。视频体积小是因为视频编码器做的是像素级别的空间和时间压缩而 JSON 做的是结构化事件描述两者的信息密度完全不同。1.1 每一条操作都带完整上下文累计起来就很可怕一个用户打开页面鼠标移动 30 次、滚动 20 次、点击 5 次、输入 20 次这还算普通操作。如果每次事件都保存完整的目标元素路径、坐标、时间戳、事件类型、对应的组件状态那么一个 3 分钟的操作流程生成 50MB JSON 完全不意外。对比同样 3 分钟的 720p 屏幕录像H.264 压缩后可能也就 20MB 左右。这里的关键不是“JSON 格式不好”而是事件录制天然会记录大量“过程信息”。视频记录的是“结果”事件录制记录的是“每个瞬间的状态变化”。过程越细回放还原度越高但数据量也越大。所以不要在体积膨胀的时候第一反应是怪 JSON先看你到底录了多少层信息。我一般会先做一次录制内容抽检把一条完整录制文件打开按字段统计体积占比。经常发现 70% 以上的体积来自 mouseover、mousemove 和 scroll 这类高频事件而这些事件对回放价值并不高。1.2 全量快照和增量快照的取舍录制回放常见的实现是页面加载时记录一次完整 DOM 快照之后所有用户操作只记录增量变化。但有些方案偷懒会在每次点击或输入后重新生成一份全量 DOM 序列化结果。这样做的后果是用户输入 50 个字符JSON 里就多了 50 份几乎相同的完整页面数据。所以优化第一步不是上压缩算法而是检查快照策略初始快照页面加载后生成一次完整快照可以做大也可以做小页面结构复杂时体积不会小。增量记录后续每次变化只记录变更节点、变更类型、变更内容而不是整页序列化。快照重建频率有些场景为了回放准确性会每隔 N 次操作重建一次全量快照方便回放中断后快速恢复。这个 N 要按业务需求调不是越大越好也不是越小越好。1.3 序列化格式本身的冗余同一个 JSON字段名占用多少、嵌套层数多少、缩进空格多少这些都会影响最终文件大小。在生产环境请关闭 pretty print不要为了调试方便把用户操作日志全量美化格式后落盘。另外字段名尽量短但要可读像mousemove这种长度还好像targetElementXPath这种长字段名在百万次事件里就是巨大的冗余。2. 回放卡成幻灯片的核心原因不是浏览器是数据结构回放卡顿的问题很多人以为是页面里的图片太多、动画太多或者电脑性能不好。其实对录制回放来说卡顿的根因往往在于回放引擎在“重建操作”而不是“播放画面”。2.1 回放引擎要做的三件事一次回放过程浏览器至少要做三件事解析 JSON把事件列表还原成内存对象。根据事件对象找到对应的 DOM 节点。执行动作比如设置滚动位置、触发点击、修改 input 的 value、修改样式。这三个步骤里第一步对几百 MB 的 JSON 做 JSON.parse 本身就是一次超高开销操作单线程解析可能直接阻塞主线程好几秒。第二步涉及 DOM 查询如果事件里没有存快速的节点索引每次都要从根节点开始用类名或 XPath 查找会随着页面深度线性增长。第三步最耗性能因为每一次 DOM 写入都会触发浏览器布局和绘制如果节奏没控制好浏览器会在极短时间内执行几百次布局计算。2.2 事件洪峰才是卡顿的真凶用户真实操作并不是匀速的。比如用户在表单里快速输入一串文字可能 2 秒内产生了 40 次 input 事件又比如用户快速滚动页面1 秒内可能产生 60 次 scroll 事件。这些事件在录制端是“产生即记录”但在回放端如果也“按原样逐条执行”就会造成事件洪峰。回放端不应该老老实实把每个事件都重放一遍而要做时间桶合并。把 50 毫秒内的事件合并成一条批量记录把 1 秒内的相同操作去重或取最后一个值这样用户感知不到差异但浏览器要执行的 DOM 操作次数可以下降一个量级。不要一上来就调整浏览器渲染参数或者换电脑测试。先用日志打印每条事件重放前后的时间戳看看到底是 JSON 解析慢、DOM 查询慢还是布局绘制慢定位到具体阶段再改。2.3 优化回放节奏的几个有效策略分帧执行把事件列表切成小批次每帧只处理一定数量的事件用 requestAnimationFrame 控制节奏避免阻塞主线程。虚拟时间轴回放时使用虚拟时间而不是真实时间。每条事件记录带时间戳回放引擎计算两个事件之间的时间差然后按比例压缩或拉长让用户可以用 2 倍速、4 倍速甚至 10 倍速浏览。懒加载快照初始 DOM 快照不要一次性全部注入 DOM可以按需渲染。先把最外层框架渲染出来等用户滚动到某个区域或达到某个时间点再渲染对应区域的节点。预解析与分片加载把大 JSON 文件按时间段或事件序号拆成多个小文件回放时按需加载。如果单个文件仍然超过几百 MB说明录制策略本身已经出了问题应该回去修数据层。3. 密码直接出现在快照里这类问题必须当安全事故处理项目里把用户密码直接展示在快照中看起来是“录到了 input 输入的内容”其实是安全边界没有控制好。任何形式的用户操作录制只要涉及表单输入就默认必须做敏感字段隔离。3.1 密码是怎么进快照的很常见的情况是录制代码对所有 input 元素的变更事件做监听拿到 event.target.value 就写入 JSON。对文本输入框来说这没问题但对 password 类型的输入框value 字段就是用户的明文密码。有些项目还会做“快照重建”也就是把当前页面的 DOM 结构整体序列化一次。如果用户正处于密码输入状态快照重建时会把密码框的 value 属性也序列化进去哪怕你平时已经处理了实时事件快照这一层的漏洞仍然存在。所以发现问题后先别急着只改回放端的展示逻辑。真正的修复必须是录制端不采集、存储端不落盘、展示端不还原。3.2 脱敏应该做在哪一层这里给一个三层过滤的固定思路录制端识别 input[typepassword]、所有包含 password、pwd、passwd、secret、token 的字段名以及你业务里的自定义敏感字段拦截 value 采集只记录“有输入”这个动作不记录内容。存储端在写入数据库或文件前增加一个清洗步骤对整个 JSON 做正则匹配扫描替换可能存在的敏感值。虽然这会额外消耗一些性能但属于必要成本。回放端展示的时候再做一次兜底过滤。不要依赖前端过滤但前端过滤能避免同一个文件被开发者打开调试时直接泄露。注意很多开源录制方案默认不启用敏感字段过滤就算文档里写了也要自己验证。不要以为引入了一个库就自动安全要实际跑一遍带密码表单的场景检查落盘文件里有没有明文内容。3.3 敏感信息治理的几个检查项检查录制配置文件里是否包含敏感字段排除列表。检查初始快照生成时是否对 password 和 textarea 里的内容做了置空或打码。检查增量事件中input 事件的 value 字段是否被统一替换为固定占位符。检查回放端如何处理已经落盘的脏数据至少要做到展示时脱敏。检查日志和调试模式下是否也做了同样的过滤防止开发环境泄露。4. 实战优化从安全、体积、流畅度三个方向依次落地建议按“先安全、再体积、再流畅度”的顺序优化。安全问题是事故级别必须排第一。体积和流畅度会影响性能和使用体验可以在同一轮优化里一起处理。4.1 先做敏感字段脱敏写一个统一的脱敏配置分成两层字段名匹配和行为匹配。字段名匹配容易理解只要触发的元素 name、id、data-field 属性包含 password、pwd、passwd、secret、token、credential、cardNumber 等关键词就判定为敏感输入录制值全部替换成***。行为匹配要特别注意有些系统会把密码框的 type 改成 text让用户能看到密码。这种情况下只靠 typepassword 识别不够需要额外判断元素是否在“密码可见”状态下被修改。更稳妥的做法是让业务方在设置密码表单时给输入框添加一个>