Node+Websocket实现消息未读之点不完的小红点
cac55 2024-10-26 08:14 18 浏览 0 评论
作者: 蓝色的秋风
转发链接:https://mp.weixin.qq.com/s/dBTog_m7xBnmMeaLE-d16g
前言
这个项目本来是我学生时代为了找工作的一个练手项目,但是没想到受到了很多的关注,star也快要破K了,这也激励着我不断去完善他,一方面是得对得起关注学习的人,另一方面也是想让自己能过通过慢慢完善一个项目来让自己提高。
Github:https://github.com/hua1995116/webchat
今天给大家带来的是基于Websocket+Node+Redis未读消息功能,可能更加偏向于实战方向,需要对Websocket和Node有一些了解,当然不了解也可以看看效果,效果链接( https://www.qiufengh.com/ )说不定会激起你学习的动力~
下面我通过自己思考的方式来进行讲解,代码可能讲的不多,但是核心逻辑都进行了讲解,上面也有github地址,有兴趣的可以进行详细地查看。自己的idea或多或少会有一些不成熟,但是我还是厚着脸皮出来抛头露脸,如果有什么建议还请大家多多提出,能让我更加完善这个作品。
设计
首先对于消息未读,大家都很熟悉,就是各种聊天的时候,出现的红点点,且是强迫症者必须清理的一个小点点,如所示。我会带大家实现一个这样的功能。
由于一对一的方式更加简单,我现在只考虑多对多的情况,也就是在一个房间(也可以称为群组,后面都以房间称呼)中的未读消息,那么设计这样的一个功能,首先我将它分成了3种用户。
- 离线用户
- 在线用户
- 在线用户且进入群组的用户
离线用户
这种场景就相当于我们退出微信,但是别人在房间里发的消息,当我们再次打开的时候依然能够看到房间增长的未读消息。
在线用户
这种场景就是相当我们停留在聊天列表页面,当他人在房间中发送消息,我们能够实时的看到未读消息的条数在增长。
场景示例。
在线用户且在房间的用户
这种场景其实就比较普通了,当别人发送新的消息,我们就能实时看到,此时是不需要标记未读消息的。
场景示例。
流程图
主要流程可以简化为三个部分,分别为用户,推送功能,消息队列。
用户可以是消息提供者也可以是消息接受者。以下就是这个过程。
当然在这个过程中涉及比较复杂的消息的存储,如何推送,获取,同步等问题,下面就是对这个过程进行详细的描述
图上的流程解释
A. 存储在Node缓存中的房间用户列表(此处信息也可以存在Redis中)
B. 存储在Redis中的未读消息列表
C. 存储在MongoDB中的未读消息列表
- 用户1进入首页。
- 用户1进入房间,重置用户在房间1的未读消息,触发更新模块去更新B未读消息列表。
- 用户1向向房间B中发送了一条消息。
- 后端需要去获取房间用户列表,判断用户是否在房间?
- 是,因为在房间中的用户已经读取了最新消息,不需要进行计数。
- 否,若用户不在房间中,更新其的未读消息计数
- 从缓存中获取用户的消息进行分发。
- 用户2登录我们的项目,从离线用户变成了在线用户。
- 用户2登录时,触发查询模块,去获取其当前在各个房间未读消息情况。
- 查询模块去查询Redis中的未读消息,若Redis中没有数据,会继续向数据库中查询,若没有则返回0给用户。
- Redis缓存将会每分钟和数据库同步一次,保证数据的持久化。
环境
- Node: 8.5.0 +
- Npm: 5.3.0 +
- MongoDB
- Redis
为什么是redis ?
介绍
Redis 是互联网技术领域使用最为广泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,是一个高性能的key-value数据库。具有性能极高,丰富的数据类型,原子,丰富的特性等优势。
redis 具有以下5种数据结构
- String——字符串
- Hash——字典
- List——列表
- Set——集合
- Sorted Set——有序集合
想要深入了解这5种存储结构可以查看http://www.runoob.com/w3cnote/redis-use-scene.html
安装
windows
http://www.cnblogs.com/jaign/articles/7920588.html
mac
brew install redis
ubuntu
apt-get install redis
redhat
yum install redis
centos
https://www.cnblogs.com/zuidongfeng/p/8032505.html
运行客户端
redis-cli
可视化工具安装
windows
https://pan.baidu.com/s/1kU8sY3P
mac
https://pan.baidu.com/s/10vpdhw7YfDD7G4yZCGtqQg
源码编译
http://docs.redisdesktop.com/en/latest/install/#build-from-source
项目中的数据结构
在本项目中我们用String 来存储用户的未读消息记录,利用其incr命令来进行自增操作。利用Hash结构 来存储我们websocket连接时用户的socket-id。
上面说了计数利用Redis的Stirng数据结构, 在Redis 我们的计数key-value是这样的。
username-roomid - number
例子: hua1995116-room1 - 1
我们的Socket-id则为Hash结构。
- socketId
- username - socketid
例子:
- socketId
- hua1995116 - En4ilYqDpk-P5_tzAAAG
MongoDB
本项目一开始就使用了MongoDB,Node天然搭配的MongoDB的优势,这里就不再进行讲解,Node操作MongoDB的模块叫做mongoose,具体的参数方法,可以查看官方文档。
https://mongoosejs.com/docs/4.x/index.html
MongoDB下载地址
https://www.mongodb.com/download-center/community
可视化下载地址
https://github.com/mrvautin/adminMongo
websocket + node 实现
下面我们通过一开始的3种用户的场景来具体说明实现的代码。
离线用户变成在线用户
客户端在登录时会发送一个login事件,以下是后端逻辑。
// 建立连接socket.on('login',async (user) => { console.log('socket login!'); const {name} = user; if (!name) { return; } socket.name = name; const roomInfo = {}; // 初始化socketId await updatehCache('socketId', name, socket.id); for(let i = 0; i < roomList.length; i++) { const roomid = roomList[i]; const key = `${name}-${roomid}`; // 循环所有房间 const res = await findOne({username: key}); const count = await getCacheById(key); if(res) { // 数据库查数据, 若缓存中没有数据,更新缓存 if(+count === 0) { updateCache(key, res.roomInfo); } roomInfo[roomid] = res.roomInfo; } else { roomInfo[roomid] = +count; } } // 通知自己有多少条未读消息 socket.emit('count', roomInfo);});
用户从离线变成在线状态,建立socket连接时候,会发送一个login事件, 服务端就会去查询当前用户的未读消息情况,从MongoDB和Redis分别查询,若Redis中没有数据,则向数据库查询。
在线用户进入房间
客户端在加入房间说话会发送一个room事件,以下是后端逻辑
// 加入房间socket.on('room', async (user) => { console.log('socket add room!'); const {name, roomid} = user; if (!name || !roomid) { return; } socket.name = name; socket.roomid = roomid; if (!users[roomid]) { users[roomid] = {}; } // 初始化user users[roomid][name] = Object.assign({}, { socketid: socket.id }, user); // 初始化user const key = `${name}-${roomid}`; await updatehCache('socketId', name, socket.id); // 进入房间默认置空,表示全部已读 await resetCacheById(key); // 进行会话 socket.join(roomid); const onlineUsers = {}; for(let item in users[roomid]) { onlineUsers[item] = {}; onlineUsers[item].src = users[roomid][item].src; } io.to(roomid).emit('room', onlineUsers); global.logger.info(`${name} 加入了 ${roomid}`);});
服务端接收到客户端发送的room事件,来重置该用户房间内的未读消息,并且该用户加入房间列表。
在房间中的用户发送消息
客户端在加入房间说话会发送一个message事件,以下是后端逻辑
socket.on('message', async (msgObj) => { console.log('socket message!'); //向所有客户端广播发布的消息 const {username, src, msg, img, roomid, time} = msgObj; if(!msg && !img) { return; } ... // 此处为向数据库存入消息 const usersList = await gethAllCache('socketId');// 所有用户列表 usersList.map(async item => { if(!users[roomid][item]) { // 判断是否在房间内 const key = `${item}-${roomid}` await inrcCache(key); const socketid = await gethCacheById('socketId', item); const count = await getCacheById(key); const roomInfo = {}; roomInfo[roomid] = count; socket.to(socketid).emit('count', roomInfo); }})
此步骤略微复杂,主要是房间中的用户发送消息,需要经过判断,哪部分用户需要计数,哪部分用户不需要计数,从图中可以看出,不在房间内的用户都需要计数。
接下来还需要推送,那么哪些用户需要实时地推送呢,对的,就是那些在线用户并且不在房间内的用户。因此在这里也需要一个判断。
这样就完美了,能够精确地给用户增加计数,并且精确地推送给需要的用户。
后记
在线演示: https://www.qiufengh.com/
github地址: https://github.com/hua1995116/webchat
推荐Vue学习资料文章:
《入口开始解读Vue源码系列(二)——new Vue 的故事》
《入口开始解读Vue源码系列(四)——实现一个基础的 Vue 双向绑定》
《入口开始解读Vue源码系列(五)——$mount 内部实现》
《入口开始解读Vue源码系列(六)$mount 实现compile parse生成AST》
《入口开始解读Vue源码系列(七)$mount 实现compile optimize标记》
《细聊single-spa + vue来实现前端微服务项目》
《细聊Single-Spa + Vue Cli 微前端落地指南「实践」》
《一文带你搞懂vue/react应用中实现ssr(服务端渲染)》
《教你Vue3 Compiler 优化细节,如何手写高性能渲染函数(上)》
《教你Vue3 Compiler 优化细节,如何手写高性能渲染函数(下)》
《Deno将停止使用TypeScript,并公布五项具体理由》
《为什么Vue3.0不再使用defineProperty实现数据监听?》
《如何写出优秀后台管理系统?11个经典模版拿去不谢「干货」》
《一个由 Vue 作者尤雨溪开发的 web 开发工具—vite》
《提高10倍打包速度工具Snowpack 2.0正式发布,再也不需要打包器》
《大厂Code Review总结Vue开发规范经验「值得学习」》
《带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」》
《「干货」Vue+高德地图实现页面点击绘制多边形及多边形切割拆分》
《细品pdf.js实践解决含水印、电子签章问题「Vue篇」》
《Vue仿蘑菇街商城项目(vue+koa+mongodb)》
《基于 electron-vue 开发的音乐播放器「实践」》
《「实践」Vue项目中标配编辑器插件Vue-Quill-Editor》
《「干货」Deno TCP Echo Server 是怎么运行的?》
《「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台》
《「实践」深入对比 Vue 3.0 Composition API 和 React Hooks》
《前端网红框架的插件机制全梳理(axios、koa、redux、vuex)》
《深入学习Vue的data、computed、watch来实现最精简响应式系统》
《10个实例小练习,快速入门熟练 Vue3 核心新特性(一)》
《10个实例小练习,快速入门熟练 Vue3 核心新特性(二)》
《教你部署搭建一个Vue-cli4+Webpack移动端框架「实践」》
《尤大大细品VuePress搭建技术网站与个人博客「实践」》
《是什么导致尤大大选择放弃Webpack?【vite 原理解析】》
《带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】》
《带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】》
《一篇文章教你并列比较React.js和Vue.js的语法【实践】》
《深入浅出通过vue-cli3构建一个SSR应用程序【实践】》
《聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总》
《【新消息】Vue 3.0 Beta 版本发布,你还学的动么?》
《Vue + Koa从零打造一个H5页面可视化编辑器——Quark-h5》
《深入浅出Vue3 跟着尤雨溪学 TypeScript 之 Ref 【实践】》
《手把手教你深入浅出vue-cli3升级vue-cli4的方法》
《Vue 3.0 Beta 和React 开发者分别杠上了》
《手把手教你用vue drag chart 实现一个可以拖动 / 缩放的图表组件》
《Vue3 尝鲜》
《2020 年,Vue 受欢迎程度是否会超过 React?》
《手把手教你Vue解析pdf(base64)转图片【实践】》
《手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】》
《深入浅出Vue3 的响应式和以前的区别到底在哪里?【实践】》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《基于Vue/VueRouter/Vuex/Axios登录路由和接口级拦截原理与实现》
《手把手教你D3.js 实现数据可视化极速上手到Vue应用》
《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】》
《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】》
《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【下】》
作者: 蓝色的秋风
转发链接:https://mp.weixin.qq.com/s/dBTog_m7xBnmMeaLE-d16g
相关推荐
- Linux :远程访问的 16 个最佳工具(一)
-
通过远程桌面协议(RDP)可以访问远程Linux桌面计算机,这是Microsoft开发的专有协议。它为用户提供了一个图形界面,可以通过网络连接连接到另一台/远程计算机。FreeRDP是...
- Guacamole安装部署_guacamole简单搭建
-
Guacamole安装部署Guacamole简介Guacamole是提供连接远程桌面的解决方案的开源项目(也可以说是一个远程桌面网关),通过浏览器就能远程操作服务器,适用于Chrome、Firefox...
- 1-FreeRTOS入门指南_freertos+lwip
-
本专栏是根据官方提供的文档进行FreeRTOS的各个功能函数的说明,以及函数的使用本专栏不涉及动手操作,只是对原理进行说明,FreeRTOS基础知识篇更新完成会对如何在开发板上进行上手实战操作。这里不...
- Windows暂停远程桌面,这些工具可替代
-
Windows暂停远程桌面,这些工具可替代近日,Windows官方宣布将于2025年5月27日起,在Windows10和Windows11应用商店中下架“Microsoft远程桌面”应用。这一消...
- 现在做 Web 全景合适吗?_前端全景
-
作者:前端藏经阁转发链接:https://www.yuque.com/xwifrr/uxqg5v/cgclx0前言Web全景在以前带宽有限的条件下常常用来作为街景和360°全景图片可查看。它可以...
- 网页直连,MSTSC远程控制Windows新姿势!
-
不用安装软件,打开浏览器就能远程办公?今天要聊的是一种颠覆传统的远程控制玩法,直接用网页连接Windows电脑,无需下载客户端,手机、平板、Mac甚至Linux都能轻松操作。这可不是吹牛,结合MSTS...
- QQ出现大面积盗号,原因已查明,请抓紧改密码
-
你没有看错,QQ又上了微博热搜,这次比较严重了,QQ出现大面积盗号,多个QQ群出现yellow信息,其次导致多位成员被踢出,并且还被封号处理,到底怎么回事?请继续往下看。在6月26日晚上10点左...
- 我在淘宝花10块钱,买到了能玩“宝可梦”的Q群机器人
-
十一月雨|文我是个没事喜欢逛淘宝的人,虽然是个不怎么好的习惯,但总是能够发现一些奇奇怪怪的东西,这次我发现的是一种Q群机器人。Q群机器人,大多是基于腾讯SmartQQ协议实现的一种能自动回复、自定...
- Metasploit最实用的攻击模块"Meterpreter"
-
Meterpreter命令详解Meterpreter是Metasploit渗透测试平台框架中功能最强大的攻击载荷模块,在最新的Metasploitv4.5.0版本中,攻击载荷模块已经达到了25...
- 手机QQ再更新,上线了一个想让人“无法回避”的新功能
-
近日,手机QQ更新了V8.2.6.700版本,苹果iOS版和安卓版手机QQ上线了一个新功能:可以实时显示对方的手机电量以及充电状态。开通电量显示也很简单,长按主页左上方的头像,在在线状态中选择我的电量...
- 「网络安全」常见攻击篇(20)——点击劫持
-
什么是点击劫持?点击劫持(Clickjacking)技术又称为界面伪装攻击(UIredressattack),是一种视觉上的欺骗手段。通常有两种方式:攻击者使用一个透明的iframe,覆盖...
- 曾利用驱动人生升级通道传播的木马下载器攻击方法再次升级
-
一、概述御见威胁情报中心1月25日再次监测到曾利用驱动人生升级通道传播的木马下载器攻击方法再升级。本次升级主要变化在于攻击模块,木马在之前的版本上,新增计划任务“DnsScan”,在其中将永恒之蓝攻击...
- QQ飞车手游:点券首个功能性宠物上架,实战稳定触发还不快入手?
-
随着版本的逐渐更新,点券宠物在道具模式发挥逐渐越来越小,曾经探讨点券宠物在道具是不是真的没有用?直到出现了波斯猫改变了,我对点券宠物在道具模式的看法,如今又一个强势点券宠物来袭,而且特性触发简单,还是...
- 工单系统设计实战(上):核心配置与效能提升
-
流程的标准化并非终点,而是研发效能持续革命的基石。当工单系统真正成为研发团队的“神经中枢”,每一次需求的精准流转、每一行代码的受控提交、每一次版本的可靠发布,都将汇聚成驱动产品持续进化的强大动力...
- 6个编辑PDF文档内容的工具(软件+网站)
-
在日常办公、学习和生活中,PDF文件因其格式稳定、跨平台兼容性强等特点,被广泛应用。但有时我们拿到PDF文件后,却发现需要修改其中的内容,总感觉有点难搞。其实PDF文档编辑修改也很简单,这里分享6个软...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)