React回滚先留证据

一次 React 页面灰度上线,最麻烦的不是 bug 本身,而是没人能快速说明 bug 影响了谁。新版本只放给 10% 用户,错误日志里有一堆组件栈,埋点里也有页面访问,但两边对不上。产品问“要不要立刻回滚”,开发只能说“感觉先回吧”。回滚按钮点下去很快,复盘却拖了两天,因为团队不知道到底是哪类用户遇到了问题,也不知道回滚之后问题是否真的消失。
这就是我说的:React 回滚先留证据。前端回滚经常被理解成发布平台能力,按钮一按,流量切回旧版本。但真实业务里,回滚之前要判断影响范围,回滚过程中要知道状态是否一致,回滚之后要证明指标已经恢复。如果没有证据,回滚只是一个带着焦虑的动作。
只看组件栈是不够的
React 错误边界能捕获一部分渲染异常,Sentry 或自研日志也能记录组件栈。但组件栈只说明“代码在哪里炸”,不说明“用户怎么走到这里”。一次回滚决策至少需要版本号、路由、用户分组、实验桶、接口状态、关键操作序列。没有这些信息,错误再多也只是噪音。
一个比较实用的做法是在应用启动时写入版本上下文。比如 commit hash、构建号、灰度批次、实验 id、设备类型都进入日志上下文。页面级埋点也要带这些字段。这样当某个版本错误率升高时,能按版本和人群聚合,而不是在所有用户日志里翻。
不要把证据都压给错误日志。很多回滚发生在“没有抛异常但体验坏了”的场景,比如按钮点击无响应、列表空白、接口重复请求、状态闪烁。这里需要用户行为埋点和性能指标。尤其是关键按钮,点击、请求发出、请求成功、视图更新这几个节点最好能串起来。
状态回滚比代码回滚难
React 页面通常不只有组件状态,还有服务端状态、本地缓存、URL 参数、表单草稿和全局 store。代码回到旧版本,不代表这些状态也能自动匹配旧逻辑。如果新版本写入了新字段,旧版本不认识;如果新版本改变了缓存 key,旧版本可能读不到;如果新版本把 URL 参数含义改了,用户刷新后仍然可能出错。
所以回滚方案里要单独写状态兼容。比如新增字段只能向后兼容,不要让旧版本看到就崩;缓存 key 变更要保留旧 key 读取;本地持久化结构要有版本号;表单草稿恢复失败时要给用户兜底。前端回滚真正怕的是“代码回去了,数据留在未来”。
状态管理库也不是答案本身。Redux、Zustand、MobX 都能保存状态,但保存什么、何时清理、如何迁移,仍然要设计。灰度功能尤其要注意:同一个用户可能上午进新版本,下午被切回旧版本。如果状态无法兼容,回滚就会制造新问题。
回滚按钮要有前置条件
我不建议把回滚做成纯人工感觉。发布平台至少应该展示几个前置证据:新版本错误率是否高于基线,核心转化是否下降,接口失败是否同步上升,影响用户是否集中在某个渠道。证据不用复杂,但要能支持判断。
更进一步,可以给回滚设置分级。轻微样式问题可以继续观察;关键链路异常要立刻回滚;数据写入错误则不仅要回滚,还要停止入口并修复脏数据。不同问题的动作不一样,不要所有告警都只对应一个“回滚”。
回滚后还要看旧指标是否回来
很多团队回滚完就松一口气,但这时还没结束。你要看新版本流量是否真的归零,错误率是否回落,用户路径是否恢复,缓存和接口是否还有遗留异常。如果回滚后指标没有恢复,就说明问题不只在前端代码,可能是接口、配置、实验或数据状态。
回滚复盘也要记录“证据缺口”。如果这次判断慢,是因为没有版本字段,就补版本字段;如果影响范围不清,就补用户分组;如果回滚后无法确认,就补验收指标。一次好的回滚复盘,不是写谁犯了错,而是让下一次少猜一点。
最后给一个简单标准:如果你无法在十分钟内回答“哪个版本、哪些用户、哪条路径、什么症状、回滚后是否恢复”,这个 React 项目的回滚证据就还不够。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。
还有一种情况是回滚后新旧资源混用。浏览器缓存、CDN、Service Worker 都可能让用户继续拿到旧 bundle。发布平台回滚成功,不代表用户端资源立即一致。因此资源版本、缓存策略和强刷方案也应该进入回滚预案。
补一个容易被忽略的证据:用户看到的配置也要记录。很多前端灰度并不只依赖代码版本,还依赖远程配置、实验平台和后端开关。如果错误日志只有前端版本,没有配置快照,回滚时就可能误判。