-
Notifications
You must be signed in to change notification settings - Fork 2
🐛 群聊文件消息已正确显示后又重复出现在会话底部 #192
Copy link
Copy link
Open
Labels
Description
反馈来源
佳佳在 PM 娃群实际使用中发现(2026-04-01)
问题描述
在群聊中发送文件消息后,文件消息已经在正确的时间位置显示。但在其他群成员持续发送消息(产生多条新 messageSeq)后,该文件消息又突然出现在会话底部,而不是保持在原来的正确位置。
注意:这不是文件上传延迟导致的初始排序问题——文件已确认发送成功并在正确位置显示过,是事后才错位到底部的。
复现场景
- 在群聊中发送一个文件(如 .md 文件)
- 确认文件消息已在会话中正确位置显示
- 群内其他成员继续发送多条文本消息
- 过一段时间后,该文件消息突然出现在会话最底部(好几条消息之后)
源码分析
排序机制
Conversation/vm.ts中消息按order字段排序fillOrder()计算方式:order = OrderFactor(10000) × messageSeqmessageSeq由 WuKongIM 服务端在收到消息时递增分配
根因定位:messageListener 缺少前置去重
Conversation/vm.ts 第301-342行,messageListener 收到消息后的处理链路:
WS 收到消息 → new MessageWrap(message) → fillOrder() → appendMessage()
appendMessage 直接将消息 push 到 messagesOfOrigin 尾部,没有先检查是否已存在相同 clientMsgNo 或 messageID 的消息。
虽然 refreshMessages() → distinctMessages() 会按 clientMsgNo 事后去重(保留前一个,删除后一个),但存在以下风险:
- WS 断连重连:WuKongIM 服务端重新推送未确认的消息(RecvPacket),如果重推的消息
clientMsgNo与本地版本不一致或为空,distinctMessages无法匹配去重 - 发送方同时收到 SendackPacket 和 RecvPacket:群消息场景下,发送方可能既收到 ack 又收到服务端推送的 RecvPacket,两个 Message 对象的
clientMsgNo来源不同(一个来自本地fromSendPacket,一个来自服务端RecvPacket)
相关代码位置(dmwork-web 仓库)
| 文件 | 行号 | 说明 |
|---|---|---|
packages/dmworkbase/src/Components/Conversation/vm.ts |
301-342 | messageListener,无前置去重 |
| 同上 | 753-785 | appendMessage,直接 push 到 messagesOfOrigin |
| 同上 | 1221-1231 | distinctMessages,按 clientMsgNo 事后去重 |
| 同上 | 620-640 | updateMessageStatusBySendAck,成功消息不重新调 fillOrder |
packages/dmworkdatasource/src/task.ts |
全文 | MediaMessageUploadTask,文件上传完成后才发送消息 |
| wukongimjssdk(v1.2.11) | ChatManager.sendWithOptions | 文件消息先触发上传任务,上传完成后才 sendPacket |
| 同上 | ChatManager.onPacket | RecvPacket 直接 notifyMessageListeners,无去重 |
附加发现:fillOrder 不一致
updateMessageStatusBySendAck()(第620行)收到成功的 SendackPacket 后:
- ✅ 更新了
message.messageSeq - ❌ 没有重新调用
fillOrder()重新计算order
这导致发送方本地消息的 order 保持临时值,与服务端基于 messageSeq 的排序不一致。刷新页面或 pullup 加载时,消息可能跳到不同位置。
建议修复方向
- 前置去重(最直接):
messageListener在调用appendMessage前,先检查messagesOfOrigin中是否已存在相同messageID的消息,已存在则更新而非追加 - fillOrder 一致性:
updateMessageStatusBySendAck成功时也调用fillOrder()重新计算 order - SDK 层:
ChatManager.onPacket处理 RecvPacket 时,检查sendingQueues中是否有相同clientMsgNo的消息,有则跳过(避免发送方重复处理)
影响范围
- 影响端:Web 端(dmwork-web)
- 影响场景:群聊中发送文件/图片等需要上传的消息
- 严重程度:P0 — 消息顺序是 IM 基础体验,错乱直接影响信息理解
Reactions are currently unavailable