1. 项目背景与技术选型目标

IM即时通讯APP的研发重点,不只是完成聊天页面和消息发送按钮,而是设计一套能够支撑实时连接、用户关系、消息存储、群组协作、多端同步和业务扩展的通信系统。类似微信的IM产品,前端展示的是好友列表、会话窗口、群聊页面、朋友圈、红包、语音通话、视频通话、文件发送等功能;后端实际需要处理长连接接入、协议解析、消息路由、ACK确认、离线消息补偿、历史消息查询、群聊扩散、未读数计算、权限校验、缓存更新和集群部署等工程问题。

整体技术方案可以采用uniapp、Vue2、Java SpringBoot、MySQL 5.7+和Redis组合。移动端和H5端使用uniapp,PC端使用Vue2,后端业务服务使用Java SpringBoot,结构化数据存储在MySQL中,在线状态、连接路由、未读数、群成员缓存等高频数据通过Redis处理。

从系统设计角度看,IM功能模块之间并不是孤立存在的。好友、单聊、群聊、群管理、消息撤回、已读未读、表情、自定义表情、文件发送、收藏、名片分享等功能,都依赖统一的账号体系、关系链模型、会话模型和消息协议。红包、钱包、朋友圈、语音通话、视频通话、多人语音会议、i18n多语言等模块,则是在基础通信能力稳定后继续扩展出的业务能力。

在技术选型阶段,研发团队需要重点关注几个问题:通信协议如何设计,Socket、WebSocket和HTTP如何分工;消息格式是否便于扩展,JSON结构如何兼容不同消息类型;消息如何保证可靠投递,ACK、重试、去重和离线补偿如何处理;群聊消息如何分发,写扩散、读扩散或混合模式如何选择;四端登录时,安卓、iOS、H5和PC端的消息状态如何同步;部署时,连接服务、业务服务、MySQL和Redis如何拆分。

因此,设计即时通讯APP时,应先明确底层通信链路、消息结构、会话结构、用户关系、群组关系、缓存边界和数据持久化方式,再逐步展开具体功能模块。这样可以避免前期只围绕页面功能开发,后期在多端同步、群聊扩展、消息可靠性和数据一致性上出现较高改造成本。

2. 技术栈总览

层级 技术选型 主要作用
移动端 / H5 uniapp 支持安卓、iOS、H5多端页面开发
PC端 Vue2 构建桌面端聊天、联系人、群组、文件等界面
后端 Java SpringBoot 处理用户、好友、群、消息、钱包、朋友圈等业务接口
数据库 MySQL 5.7+ 存储用户、关系链、群组、消息索引、钱包流水等结构化数据
缓存 Redis 存储在线状态、连接路由、未读数、群成员缓存、分布式锁等
通信协议 Socket / WebSocket / HTTP 分别承载APP长连接、浏览器实时通信和普通业务接口
安全传输 SSL / TLS 保护登录、消息、钱包、文件等传输数据

3. 系统分层设计

从工程结构上看,一个即时通讯APP可以拆成以下几个核心层级。

3.1 终端展示层

终端层主要包含安卓、iOS、H5和PC端。移动端与H5端采用uniapp,PC端采用Vue2。

终端层需要处理的内容包括:

  • 会话列表渲染
  • 单聊和群聊消息气泡
  • 文本、图片、语音、视频、文件消息展示
  • 表情和自定义表情面板
  • 红包消息卡片
  • 名片消息卡片
  • 消息撤回状态
  • 引用消息展示
  • @群成员提醒
  • 未读数展示
  • 朋友圈动态流
  • 钱包和红包记录页面
  • 多语言文本切换

IM前端页面的复杂度通常高于普通业务系统,因为消息状态会频繁变化。比如一条消息可能经历“发送中、发送成功、发送失败、已送达、已读、已撤回”等状态,前端需要维护本地消息列表和服务端消息状态之间的一致性。

3.2 接入通信层

通信层负责处理实时连接。系统可以支持一端口可插拔多协议,包括Socket自定义IM协议、WebSocket和HTTP。

Socket自定义协议适合APP端长连接通信,WebSocket适合H5和PC端,HTTP适合用户资料、好友列表、群资料、朋友圈、钱包流水、收藏记录等普通接口。

通信层通常需要处理:

  • 用户连接鉴权
  • 心跳检测
  • 断线重连
  • 消息解包与编码
  • 连接路由维护
  • 用户在线状态维护
  • 消息ACK确认
  • 协议适配与转发

连接建立后,服务端可以将用户ID、设备ID、连接ID、节点ID和协议类型写入Redis。这样在消息投递时,可以根据用户在线状态判断是实时投递还是写入离线消息。

4. 消息协议设计

IM系统中,消息格式建议保持简洁,使用JSON结构可以降低多端解析成本,也便于后续扩展新的消息类型。

示例:普通文本消息结构可以设计如下:

{
  "cmd": "chat",
  "msgId": "202606151800000001",
  "conversationId": "single_10001_10002",
  "fromUserId": "10001",
  "toId": "10002",
  "chatType": "single",
  "msgType": "text",
  "content": {
    "text": "这是一条文本消息"
  },
  "clientSeq": 12,
  "serverSeq": 1024,
  "sendTime": 1781517600000
}

字段说明:

字段 含义
cmd 消息命令,例如chat、ack、revoke、read
msgId 全局唯一消息ID
conversationId 会话ID
fromUserId 发送人ID
toId 接收人ID或群ID
chatType 聊天类型,single表示单聊,group表示群聊
msgType 消息类型,例如text、image、file、red_packet
content 消息正文
clientSeq 客户端本地序号
serverSeq 服务端递增序号
sendTime 消息发送时间

对于图片、文件、红包、名片、引用消息等类型,可以在msgTypecontent中扩展。


5. 消息可靠性流程

消息可靠性是IM系统的核心能力。一个基础流程可以拆成以下几步:

  1. 客户端生成本地消息,状态为“发送中”
  2. 客户端通过长连接发送消息到服务端
  3. 服务端校验用户身份、会话关系和消息格式
  4. 服务端生成全局消息ID和服务端序号
  5. 服务端写入消息存储
  6. 服务端返回发送ACK
  7. 接收方在线时实时投递
  8. 接收方离线时进入离线消息范围
  9. 接收方上线后同步离线消息
  10. 接收方阅读后回传已读回执

示例:前端WebSocket接收消息与ACK确认逻辑:

const ws = new WebSocket("wss://im.example.com/ws");

ws.onopen = () => {
  ws.send(JSON.stringify({
    cmd: "auth",
    token: "login-token",
    deviceId: "pc-10001"
  }));
};

ws.onmessage = (event) => {
  const packet = JSON.parse(event.data);

  if (packet.cmd === "chat") {
    appendMessage(packet.data);
    sendAck(packet.data.msgId);
  }

  if (packet.cmd === "revoke") {
    updateMessageRevokeStatus(packet.data.msgId);
  }

  if (packet.cmd === "read") {
    updateMessageReadStatus(packet.data.conversationId);
  }
};

function sendAck(msgId) {
  ws.send(JSON.stringify({
    cmd: "ack",
    msgId,
    ackTime: Date.now()
  }));
}

这里的ACK不是简单的前端提示,而是消息可靠性链路的一部分。服务端可以根据ACK状态判断消息是否成功投递,客户端也可以根据服务端ACK更新消息状态。

6. 好友模块设计

 宠友IM好友模块是关系链基础。常见功能包括添加好友、好友申请、同意申请、拒绝申请、删除好友、拉黑、修改备注、查看资料、名片分享等。

好友关系建议采用双向关系表设计。用户A添加用户B后,可以生成两条关系记录,分别用于A查看B、B查看A。这样在查询联系人列表时效率更高,也方便处理备注、黑名单、删除关系等独立状态。

扫一扫添加好友可以通过二维码中的短码、临时票据或加密字符串完成,不建议直接暴露数据库主键。服务端解析二维码内容后,再返回用户资料或好友申请页面。


7. 单聊模块设计

单聊是点对点通信。它需要支持文本、图片、语音、视频、文件、表情、红包、名片、引用消息等多种消息类型。

单聊技术重点包括:

  • 会话ID生成规则
  • 消息ID生成规则
  • 离线消息同步
  • 历史消息分页
  • 消息去重
  • 多端同步
  • 已读回执
  • 消息撤回
  • 文件消息权限校验

历史消息分页建议使用游标方式,例如基于serverSeqmsgId向前查询,不建议只使用页码分页。因为IM消息是实时写入的,页码分页容易因为新消息插入导致数据重复或遗漏。

8. 群聊与群管理模块设计

群聊比单聊复杂,主要难点在于群成员管理、消息扩散、权限判断和未读统计。

群管理功能包括:

  • 创建群
  • 修改群名称
  • 修改群头像
  • 群公告
  • 群二维码
  • 邀请成员
  • 移除成员
  • 设置管理员
  • 转让群主
  • 群禁言
  • 入群审核
  • 扫一扫加入群聊

群成员表可以参考如下结构:

CREATE TABLE im_group_member (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  group_id BIGINT NOT NULL COMMENT '群ID',
  user_id BIGINT NOT NULL COMMENT '用户ID',
  role TINYINT NOT NULL DEFAULT 0 COMMENT '0成员 1管理员 2群主',
  group_nickname VARCHAR(64) DEFAULT NULL COMMENT '群内昵称',
  mute_until BIGINT DEFAULT 0 COMMENT '禁言截止时间',
  join_time BIGINT NOT NULL COMMENT '加入时间',
  status TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 2已移除 3主动退出',
  UNIQUE KEY uk_group_user (group_id, user_id)
);

群消息发送时,服务端需要先判断用户是否属于该群、群是否有效、用户是否被禁言。校验通过后,再写入群消息表并进行消息分发。

对于小群,可以采用写扩散方式,为每个成员生成消息收件记录。对于大群,可以采用读扩散或混合模式,减少写入压力。实际项目中可以根据群规模、消息频率和查询性能进行选择。

9. @群成员、引用回复与名片分享

@群成员功能可以在消息体中保存被@用户ID列表,例如:

{
  "msgType": "text",
  "content": {
    "text": "@张三 请确认一下文件内容",
    "atUserIds": ["10003"]
  }
}

客户端根据atUserIds进行高亮显示,被@用户可以在会话列表中看到特殊提醒。

消息引用和回复适合解决群聊上下文混乱的问题。消息体中可以保存原消息ID、原发送人、原消息摘要等字段。即使原消息内容较长,引用区域也可以只展示摘要。

名片分享可以作为一种特殊消息类型。消息体中保存被分享用户的ID、昵称、头像快照。接收方点击名片后,再通过用户接口查询最新资料。

10. 红包与钱包模块设计

红包和钱包属于资金相关模块,技术设计需要更关注一致性和流水可追踪。

红包功能包括:

  • 单聊红包
  • 群红包
  • 普通红包
  • 拼手气红包
  • 红包领取记录
  • 红包过期退回
  • 红包状态查询

钱包功能包括:

  • 余额
  • 冻结金额
  • 充值记录
  • 提现记录
  • 交易流水
  • 红包收支记录

群红包领取属于高并发场景。服务端需要防止重复领取、超额领取和并发扣减异常。常见处理方式是使用Redis原子操作或分布式锁控制领取流程,最终将领取记录和钱包流水落入MySQL。

钱包流水表需要记录交易类型、交易方向、金额、交易前余额、交易后余额、关联业务ID、创建时间等字段。这样可以保证每一笔余额变化都有来源可追踪。

11. 消息撤回、已读未读与多端同步

消息撤回需要服务端校验消息归属、发送人身份、撤回时间范围和消息类型。撤回成功后,服务端向相关用户发送撤回通知,客户端将原消息替换为“该消息已撤回”状态。

已读未读可以分为单聊和群聊两种处理方式。

单聊中,可以记录双方最后已读消息游标。
群聊中,如果逐条记录每个成员的已读状态,数据量会比较大。更常见的做法是记录每个成员在群内的最后已读serverSeq,再通过消息序号计算未读数量。

多端同步需要处理同一账号在手机、H5、PC同时在线的情况。例如用户在PC端读完一个会话后,手机端也应该同步清除未读数。实现上可以将同账号下不同设备都注册到连接路由中,消息状态变化时向其他设备广播同步事件。

12. 表情、自定义表情、文件发送与收藏

表情模块可以分为系统表情和自定义表情。系统表情一般内置在前端资源中,自定义表情需要后端保存图片地址、排序、状态和所属用户。

文件发送需要处理上传、存储、消息发送和下载权限。文件消息体中可以保存文件名、文件大小、文件类型、文件URL、文件hash等信息。文件hash可以用于去重、秒传和完整性校验。

收藏功能可以覆盖文本、图片、文件、语音、链接、名片等内容。收藏时建议保存内容快照,而不是只保存原消息ID。因为原消息可能被撤回、删除或清理,保存快照可以保证收藏内容的可用性。

13. 朋友圈模块设计

朋友圈属于基于好友关系链的内容模块。常见功能包括发布图文动态、点赞、评论、删除动态、动态详情、好友动态流和可见范围设置。

朋友圈的数据可以拆成动态主表、图片表、点赞表、评论表和可见范围表。动态列表查询时,需要结合好友关系、屏蔽关系和动态权限进行过滤。

可见范围通常包括:

  • 公开
  • 仅好友可见
  • 部分好友可见
  • 不给谁看

为了提高列表性能,可以在动态主表中冗余点赞数、评论数、图片数量等字段。详情页再加载完整评论和点赞列表。

14. 语音通话、视频通话与多人语音会议

语音通话和视频通话一般由信令服务和媒体服务共同完成。IM系统主要负责信令部分,例如发起通话、接受通话、拒绝通话、取消呼叫、挂断、忙线、超时等事件。

多人语音会议不同于普通一对一通话。它需要会议房间、成员状态、静音状态、主持人控制、加入退出通知等能力。群聊中发起多人语音会议时,可以先创建会议房间,再向群成员发送会议邀请消息。成员加入后,服务端维护会议成员状态,并同步给其他参会用户。

15. i18n多语言包设计

i18n多语言包适合需要多地区使用的IM系统。前端可以将菜单、按钮、提示语、错误信息、消息状态统一抽离成语言Key。

例如:

{
  "chat.send": "发送",
  "chat.revoke": "撤回",
  "group.mute": "禁言",
  "wallet.balance": "余额",
  "message.read": "已读",
  "message.unread": "未读"
}

后端接口也可以根据请求头中的语言参数返回不同语言的错误提示。这样后续增加语言时,不需要大量修改业务代码。

16. 部署、集群与扩展设计

部署方式可以根据业务规模分为单机部署和集群部署。

开发或测试环境中,后端服务、IM服务、MySQL和Redis可以部署在同一台机器上,便于调试和一键启动。

正式环境中,可以将系统拆成多个服务:

  • IM连接服务
  • 业务API服务
  • 文件服务
  • MySQL数据库
  • Redis缓存
  • 静态资源服务
  • PC端前端服务
  • H5前端服务

集群部署时,IM连接节点可以横向扩展。用户连接到不同节点后,需要通过Redis或统一路由服务维护用户在线状态和连接位置。消息投递时,如果接收方连接在其他节点,需要通过节点间通信完成跨节点投递。

SSL/TLS加密传输可以用于HTTP、WebSocket和Socket协议,保护登录、聊天、红包、钱包和文件传输过程中的数据安全。

17. API接口与二次开发边界

一个完整的IM系统通常需要提供以下接口模块:

接口模块 主要内容
用户接口 登录、注册、用户资料、头像、昵称
好友接口 好友申请、好友列表、删除好友、拉黑
群接口 创建群、群成员、群公告、禁言、入群审核
消息接口 历史消息、离线消息、撤回、已读未读
钱包接口 余额、流水、充值、提现
红包接口 发红包、领红包、红包记录
文件接口 上传、下载、文件消息
朋友圈接口 发布动态、点赞、评论、动态流
收藏接口 收藏消息、收藏文件、收藏图片
i18n接口 语言包、语言切换

如果项目代码需要支持可商用、二次开发和独立部署,研发团队应重点关注代码结构、数据库表结构、接口文档、协议文档、部署文档和配置说明。只有前端、后端、数据库、缓存、协议和部署链路都具备清晰边界,后续业务扩展才会更可控。

18. 技术落地时需要重点关注的工程问题

在实际研发即时通讯APP时,前期可以先完成账号体系、好友关系、单聊、群聊、消息持久化、离线消息和多端同步。红包、钱包、朋友圈、音视频通话、多人语音会议等模块可以在基础通信链路稳定后逐步接入,避免一开始把所有业务耦合在同一套消息逻辑中。

18.1 消息表与会话表需要提前规划

消息数据量增长速度通常很快,单聊、群聊、文件、图片、语音、红包、名片等都可能进入消息体系。设计数据库时,可以将会话表、消息主表、消息扩展表、用户会话表分开处理。

会话表主要记录会话ID、会话类型、最后一条消息、最后更新时间等信息。消息表主要记录消息ID、发送人、接收对象、消息类型、消息内容、服务端序号、发送时间等信息。用户会话表可以记录每个用户的未读数、置顶状态、免打扰状态、草稿内容和最后已读位置。

这样设计后,聊天列表查询、历史消息分页、未读数统计、多端同步都会更清晰。

18.2 Redis缓存需要控制边界

Redis适合保存在线状态、连接路由、群成员缓存、未读数、红包领取锁、验证码、临时Token等高频数据,但不适合替代MySQL作为最终数据源。

例如用户在线状态可以存储为:

im:online:user:{userId} -> nodeId、connectionId、deviceId、lastActiveTime

群成员缓存可以存储为:

im:group:members:{groupId} -> userId list

未读数可以存储为:

im:unread:{userId}:{conversationId} -> unreadCount

缓存设计需要考虑过期时间、缓存更新、缓存击穿和数据回源。群成员变更、用户退出登录、消息已读、红包领取等操作,都需要同步处理缓存状态。

18.3 群聊扩散策略需要根据规模调整

小群和大群不适合使用完全相同的消息扩散方式。几十人以内的小群,可以采用写扩散方式,在消息发送时为每个群成员生成收件记录,查询未读和历史消息都比较直接。

如果群规模较大,写扩散会带来明显写入压力。此时可以考虑读扩散或混合扩散模式。群消息只写一份,用户读取时根据加入群时间、最后已读位置和消息序号进行拉取。对于活跃成员,可以结合缓存维护未读状态,减少频繁扫描数据库。

18.4 多端同步要独立成事件机制

四端支持意味着同一个账号可能同时登录安卓、iOS、H5和PC端。用户在任意端发送消息、撤回消息、阅读消息、收藏消息、删除会话,都需要同步到其他在线设备。

这类能力不建议写散在各个业务接口中,可以统一设计为设备同步事件,例如:

{
  "cmd": "sync",
  "event": "conversation_read",
  "userId": "10001",
  "conversationId": "single_10001_10002",
  "readSeq": 1088,
  "syncTime": 1781517600000
}

服务端在处理状态变化后,将同步事件推送给同账号下其他在线设备。这样可以保持手机端、H5端和PC端的会话状态一致。

18.5 钱包和红包需要独立事务链路

红包和钱包不要直接混在普通消息发送逻辑中。红包消息可以作为聊天消息展示,但红包创建、余额扣减、领取记录、钱包流水必须走独立事务链路。

发红包时,先完成余额校验和红包记录创建,再发送红包消息。领红包时,先判断红包状态、剩余金额、剩余数量、用户是否已领取,再写入领取记录和钱包流水。聊天消息只负责展示红包卡片,不负责决定资金状态。

18.6 文件消息需要考虑权限和生命周期

文件发送并不是简单上传一个URL。文件消息需要记录文件名、文件大小、文件类型、文件hash、上传用户、所属会话、上传时间和访问权限。

如果用户退出群聊,是否还能下载历史文件;如果消息被撤回,文件是否继续保留;如果文件被收藏,原文件过期后收藏是否还能访问,这些都需要在文件生命周期中提前定义。

18.7 i18n多语言不只处理前端文本

i18n多语言包除了前端按钮、菜单、提示语之外,还需要考虑后端错误提示、系统通知、消息状态文案和钱包流水类型文案。

例如“红包已领取”“消息已撤回”“群主已开启全员禁言”“文件不存在或已过期”等提示,如果只写死在后端或前端,后续增加语言会增加维护成本。更合理的方式是前后端使用统一语言Key,再根据用户语言环境渲染对应内容。

18.8 部署配置需要区分开发、测试和正式环境

即时通讯系统通常涉及HTTP服务、WebSocket服务、Socket服务、MySQL、Redis、文件服务、PC端静态资源、H5端静态资源等多个部分。即使支持一键启动,也需要把配置项拆清楚。

常见配置包括:

  • 数据库连接
  • Redis连接
  • IM服务端口
  • WebSocket地址
  • Socket端口
  • 文件上传路径
  • SSL/TLS证书
  • 日志路径
  • 消息存储策略
  • 离线消息保留时间
  • 钱包交易开关
  • 多语言默认配置

配置结构清晰后,后续从单机部署切换到集群部署会更容易,也方便研发团队排查线上问题。

市面上已有成熟的示例—宠友 IM宠友(IM即时通讯)app,支持语音、文件、图片、视频等多种类型消息的发送,安全可靠,交流轻松,私有化部署,快速开发,极简部署,支持群聊管理、语音视频通话...功能https://www.chongyou.info/1/product/im.html

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐