核心矛盾是同一用户多端登录后消息状态不一致,因uni-app默认将各app实例视为独立客户端,未实现服务端统一的消息id(雪花算法)、sequence序号、未读数同步及ack重传机制。

uni-app App端多终端同步的核心矛盾在哪
不是WebSocket连不上,而是「同一用户在多个App实例(比如手机+平板)登录后,消息状态不一致」。典型表现:手机上已读的消息,在平板上仍显示未读;或者新消息只推到其中一台设备。根本原因在于uni-app默认把每个App实例当成独立客户端,没做会话级状态收敛。
必须由服务端统一分配消息ID和序列号
客户端生成new Date().getTime()或Math.random()作为消息ID是灾难源头。不同设备时间不同步、随机数重复概率高,会导致服务端无法排序、前端渲染错乱。
- 服务端必须用雪花算法(Snowflake)或数据库自增+业务前缀生成全局唯一
messageId - 每条消息还需带一个严格递增的
sequence字段,用于跨设备按序合并 - 前端收到消息后,不能直接
push进列表,要先按sequence插入再去重
本地未读计数必须和服务端对齐,不能靠前端累加
很多项目用Vuex存一个unreadCount变量,每次收消息就++,这是错的。用户在另一台设备点开聊天页时,这个数字早已失效。
- 每次进入会话页,必须调用服务端API拉取该会话当前真实未读数,例如
GET /api/conversation/:id/unread - 标记已读操作必须走服务端确认,例如
POST /api/conversation/:id/read,返回成功后再清本地角标 - TabBar角标不要依赖本地缓存,
uni.setTabBarBadge前务必查一次服务端汇总未读数
心跳+ACK机制防止消息丢失,尤其在切后台时
App切后台后,系统可能直接kill掉WebSocket连接,但用户感知不到。等他切回来,中间漏掉的消息不会自动补发——除非你主动管。
- 前端需实现心跳包(如每30秒发
{"type":"ping"}),服务端回{"type":"pong"} - 每条消息发出后,启动定时器等待服务端
ACK;超时未收则重发,最多2次 - App从后台回到前台时,主动触发
GET /api/messages/since?last_seq=xxx拉取断线期间消息











