Lee's Blog
  • 首页
  • 博客
  • 作品
  • 成长
  • 学习
  • 打榜
  • 练习
  • 关于
登录 / 注册
✦

保持联系

关注我的最新动态

GitHubbilibili

© 2026 Lee's Blog

首页/博客/EZTor/一次关于通信的探索
一次关于通信的探索
EZTor2026年5月31日3 分钟阅读

一次关于通信的探索

前端
X微博

✨ 记一次实时聊天消息重复显示 BUG 的修复

🐛 问题现象

项目中的实时聊天功能出现了一个诡异的 BUG:

用户发送消息后,发送方视角会看到两条相同的消息。但刷新页面后,又恢复正常只显示一条。

🔍 这个问题只在发送方出现,其他用户看到的都是正常的单条消息。


🏗️ 技术架构

聊天功能采用的技术方案:

模块 技术
前端 React + Next.js
实时通信 SSE (Server-Sent Events)
后端 Next.js API Routes + Prisma ORM

📨 消息流转流程

graph LR
    A[用户发送消息] --> B[POST API 保存到数据库]
    B --> C[后端 broadcastMessage 通过 SSE 广播]
    C --> D[前端 SSE 监听器接收广播]
    D --> E[更新 UI]

🔬 根本原因分析

经过代码审查,发现问题出在消息被添加了两次:

📍 第一次添加:POST 响应

// handleSend() 中,POST 成功后立即添加(乐观更新)
const data = await res.json()
if (data.success) {
  setInput('')
  setMessages(prev => [...prev, data.data])  // ← 第一次添加
}

📍 第二次添加:SSE 广播

// useEffect 中的 SSE 监听
eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data)
  if (data.type === 'message') {
    setMessages(prev => [...prev, data.data])  // ← 第二次添加
  }
}

🤔 为什么其他人看不到重复?

角色 消息来源 结果
发送方 POST 响应 ✅ + SSE 广播 ✅ 两条消息 ❌
其他用户 只有 SSE 广播 一条消息 ✅

💡 因为 POST 响应只在发送方本地执行,而 SSE 广播会推送给所有订阅者(包括发送方自己)


🛠️ 解决方案

给两处添加消息的逻辑都加上 id 去重检查:

SSE 广播处理

if (data.type === 'message') {
  setMessages(prev => {
    if (prev.some(m => m.id === data.data.id)) return prev
    return [...prev, data.data]
  })
}

POST 响应处理

if (data.success) {
  setInput('')
  setMessages(prev => {
    if (prev.some(m => m.id === data.data.id)) return prev
    return [...prev, data.data]
  })
}

✅ 这样无论消息先从哪个通道到达,都能保证不会重复添加。


📚 经验教训

1️⃣ 乐观更新 + 实时广播是常见陷阱

使用乐观更新提升用户体验时,如果后端同时会广播消息给发送者,就容易出现重复。需要在设计阶段就考虑去重机制。

2️⃣ 基于唯一标识去重是最可靠的方案

使用消息 ID 去重比使用时间戳或内容比对更可靠,因为 ID 是唯一的,而内容可能相同。

3️⃣ 测试时要关注发送方视角

实时消息功能的测试,不仅要验证接收方看到的消息是否正确,也要验证发送方自己看到的是否正确。


🎯 总结

这个 BUG 的本质是 乐观更新与实时广播的冲突。修复方案很简单,但找到根因需要理解整个消息流转链路。

✨ 建议:在开发实时通信功能时,在设计阶段就明确消息的添加时机和去重策略,避免类似问题。

← 上一篇黑客杂口杂口~下一篇 →TTS大便样

相关文章

  • 退出后重登卡在"登录中":一次靠 Network 面板定位的 NextAuth session 时序问题约 5 分钟
  • 用户说"第一天的闪卡更好玩"——一次把 bug 当需求改的复盘约 6 分钟
  • meteorological 变成了 neteorological?记一次长单词被"削头"的 UI 排查约 6 分钟

评论

需要登录账号才能发表评论。

  • 加载中…

本页内容

  • ✨ 记一次实时聊天消息重复显示 BUG 的修复
  • 🐛 问题现象
  • 🏗️ 技术架构
  • 📨 消息流转流程
  • 🔬 根本原因分析
  • 📍 第一次添加:POST 响应
  • 📍 第二次添加:SSE 广播
  • 🤔 为什么其他人看不到重复?
  • 🛠️ 解决方案
  • SSE 广播处理
  • POST 响应处理
  • 📚 经验教训
  • 1️⃣ 乐观更新 + 实时广播是常见陷阱
  • 2️⃣ 基于唯一标识去重是最可靠的方案
  • 3️⃣ 测试时要关注发送方视角
  • 🎯 总结