← 返回生产场景

💬 IM 即时通讯

WebSocket / 已读未读 / 消息可靠性 / 离线消息

📨消息可靠性(不丢消息)核心
消息发送后对方一定要收到。网络可能断、用户可能离线。怎么保证?
环节问题解决
发送→服务器网络断了发不出去客户端本地存+重试,ACK确认
服务器存储消息要持久化存DB后才返回发送成功
服务器→接收方对方不在线/连接断了离线消息表,上线后拉取
接收方确认收到了但展示前崩溃客户端ACK,服务器标记已送达
// 消息表设计 // message 表:id, from_id, to_id, content, create_time // message_ack 表:message_id, user_id, status(SENT/DELIVERED/READ) // 每条消息对应每个接收方一条 ack 记录 // 发送消息 public Message sendMessage(Long fromId, Long toId, String content) { Message msg = new Message(fromId, toId, content); messageMapper.insert(msg); // 1. 先存DB(持久化) boolean online = wsService.isOnline(toId); if (online) { wsService.send(toId, msg); // 2. 在线→WebSocket推送 } // 3. 不在线→等对方上线后拉取离线消息 return msg; // 返回给发送方=发送成功 }
📖已读未读
微信那种"双蓝勾"怎么实现。
// 客户端打开聊天页面时,调接口标记已读 POST /api/messages/read { "peerId": 123 } // 服务器更新 ack 状态 public void markAsRead(Long userId, Long peerId) { ackMapper.updateStatus(userId, peerId, "READ"); // UPDATE message_ack SET status='READ' // WHERE user_id=? AND message_id IN (对方发给我的消息) // 通知发送方:对方已读 wsService.send(peerId, new ReadReceipt(peerId, userId)); }
📱离线消息
用户不在线时,消息存在哪?上线后怎么拉?
// 上线时拉取离线消息 public List<Message> getOfflineMessages(Long userId) { // 查发给这个用户但还没 DELIVERED 的消息 return messageMapper.findUndelivered(userId); // 推送后批量更新为 DELIVERED }
核心:消息先存DB再推送(不丢),ACK确认(不重复),离线消息拉取(不漏)。
生产场景 · IM即时通讯 · 全栈资料库