web技术分享| 一人一天一个可移植的实时聊天系统
在开始打造我们自己的实时聊天系统之前,我们需要先思考🤔几个问题:
- 用户体量大概多少?如何扩容?
- 用户分布的区域?
- 如何保证消息(低延时、必)送达?
做过 IM 或信令的小伙伴都知道,实时传输对服务端有着颇高的要求。就以社交 APP 为例,每秒种要处理成百上千甚至更多的文字和图片的传输;弱网丢包的情况要保证消息的完整性的同时还要确保消息已送达;这其中的技术原理和解决方案不是一个 WebSocket
所能涵盖的。
就消息必达而言,系统除了要有择优链路能力以外,还要具备多活链路。比如:一旦有一条链路出现问题,那么该消息就不一定能够送达。然而现实环境往往必我们想象中理想环境来的更糟糕和残酷,与此同时我们还要面对:网络丢包、用户量指数上升并发上不去,甚至系统宕机等等。
因此,要打造一个怎样的聊天系统,取决于我们产品的需求,根据需要选择集群部署的数量、节点的分布等诸多因素。
实时聊天系统应具备的特性
- 高并发
- 低延时
- 消息必达
- 弱网抗性
- 集群部署
- 消息推送(可选)
实时聊天系统应具备的功能
- 点对点消息
- 群组消息
- 呼叫邀请
现在的社交 APP 玩法十分丰富,提供图文传输还加入了实时通讯模块,衍生出了直播连麦、主播 PK等诸多玩法,其中很大一部分都是通过自定义实时消息来完成。举个简单的例子:微信电话,A 给 B 发送一条带状态的消息、B 接收或者挂断操作之后,状态会被锁定之后无法变更,系统再将结果发送给 A,这个过程我们称之为呼叫邀请。
总之,实时消息不仅能带来通讯便利,同时还能辅助我们丰富我们的业务流程。
Vue3 + Tailwind + RTM = 实时聊天系统
项目说明
本项目 0 业务代码,因此只能通过指定几个固定的频道房间,来演示群组消息,大家如果有需要可以对接自己的业务系统替换项目中的随机头像、随机昵称、个性签名等数据;完善点对点消息、呼叫邀请等功能;同时还可以通过 RTM 的自定义消息进行广播处理更多复杂的情形。
源码
源码请查看
使用 Vite 构建 Vue3 项目
使用 Vite
构建一个 Vue3
项目,详情参考官方文档。
创建项目
# npm 6.x
npm init @vitejs/app my-chat-app --template vue
# npm 7+, 需要额外的双横线:
npm init @vitejs/app my-chat-app -- --template vue
# yarn
yarn create @vitejs/app my-chat-app --template vue
安装依赖
cd my-chat-app
npm install
npm run dev
TailWind + TailWindComponents = UI
为什么我们要选择 tailwindcss
?
tailwindcss
不仅节省了编写 css 的时间,还避免了命名烦恼,同时tailwindComponents 提供了很多免费(使用 tailwind 开发)的 UI
组件,我们可以从中找到一些现成的 UI
组件,何乐而不为呢?比如:下面是我们从tailwindComponents 查找到的一些 chat 相关的组件。
安装 tailwindcss
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
自动生成 tailwind 的配置文件
npx tailwindcss init -p
配置 tailwindcss
这里就不做代码的搬运工了,详情请参考官方文档 ,中文请参考中文文档。
集成 RTM 模块
项目使用的 RTM SDK,相关 API 请查看官方文档,大家可以根据需求替换。
安装 RTM
npm install ar-rtm-sdk -D
导入 RTM SDK
import ArRTM from "ar-rtm-sdk"
创建客户端
const rtmClient = ArRTM.createInstance(Config.RTM_APP_ID, {
// 设置日志级别
logFilter: ArRTM.LOG_FILTER_OFF
});
登录 RTM 系统
// 随机用户 ID,可以对接自己业务系统中的 UID
const randomUserId = '' + Math.ceil(Math.random() * Math.pow(10, 10));
const uid = await rtmClient.login({
uid: randomUserId
});
加入群组&监听群组消息回调
// 创建群组
const rtmChannel = rtmClient.createChannel(group.groupId);
// 加入群组
await rtmChannel.join();
// 监听群组消息
rtmChannel.on("ChannelMessage", (message, peerId, messagePros) => {
if (message.text) {
// 解析消息内容
const msgObj = JSON.parse(message.text);
// TODO...(例如,将消息显示到页面上)
}
});
根据业务拓展
- 点对点消息
当对接业务系统后,可以使用业务中的 UID 作为 RTM 的 UID 登录,可以根据 UID 定向发送点对点消息。 - 实时音视频通话
当对接业务系统后,可以向指定 UID 的用户发起呼叫邀请,在对方接收之后,双方加入同一个音视频通讯的房间,前提是项目需要集成音视频通讯的模块。