前端架构

幂等前端事件:重复 WebSocket 消息为什么不能重复弹通知

为消息 ID、业务实体、会话版本和终态设计去重,处理重发、重连回放、双监听器与用户重复点击,不让副作用执行两次。

好的实现不会依赖用户反复刷新碰运气,而会让每个阶段有明确输入、输出、超时和终态。 网络协议常用至少一次送达,前端也可能因热更新或 bfcache 重复注册监听。把“收到消息”直接等同于“弹通知并创建任务”,同一事实就会产生多次副作用。

前端架构的核心不是目录层级,而是状态由谁拥有、事件能否重复执行、旧异步结果如何失效,以及卸载后监听器和资源是否真正归零。

先定义系统契约

先从数据和协议能保证的事实出发,再决定界面承诺。下面的规则都应有明确所有者、边界值和兼容策略,不能只存在于某次代码评审的口头共识里。

  • 协议消息带稳定 event ID,store 在应用副作用前记录已处理版本。
  • 业务实体按 request ID 或 transfer ID upsert,重复消息只刷新同一记录。
  • 按钮提交生成 intent ID 并在终态前禁用相同意图,而非仅靠防抖。

幂等的重点不是藏掉重复 UI,而是让实体更新和外部副作用都按稳定 ID 执行一次,重试才会真正安全。

哪些情况会破坏契约

最值得优先排查的是会静默留下错误事实的故障:界面看似恢复,底层队列、权限或计数却已分叉。这类问题通常在下一次动作才暴露。

  • 去重集合只在内存,刷新后的服务器回放再次产生同一通知。
  • 用消息文本去重,两个不同用户发送“你好”时第二条被错误吞掉。
  • 先执行下载再写已处理标记,页面崩溃后重放会下载第二次。

如何逐条验证契约

验证时同时观察两端状态、持久化记录和可观测指标。单看某个按钮或一次接口响应,无法证明整个闭环成立。

  1. 每种事件重复投递、乱序投递并跨刷新回放,断言实体与通知数量。
  2. 同时触发两次按钮点击与服务端重试,确认只有一个 intent 和一次外部副作用。
  3. 清理去重历史的过期边界,旧会话事件过期后仍不能修改新实体。

最终结果应同时满足正确性、可恢复性和可解释性。任何一项只能依赖刷新页面或工程师猜测,都说明协议闭环仍不完整。

把方法变成一次真实连接

打开 uCopy,让两台设备在浏览器里安全连接并开始传输。

开始免费使用