工作中经常看到别人使用和接触websocket
、但是自己的工作又用不上、于是便想着做一个个人项目来学习websocket
、恰巧看到了一个用websocket
打造的音乐聊天室项目、于是便从零开始开发了这样一个音乐聊天室大厅,想记录下一个大概的个人项目成型,也顺便分享与大家。
在我们日常的开发中,接触最多的就是http
协议了, http
协议是用在应用层的协议,他是基于tcp
协议的,http
协议建立链接也必须要有三次握手才能发送信息。在这种场景下,服务端是被动的,他不能去对客户端操作与通信,只能等待客户端主动发起,这种场景也很多件,在日常开发中,部分时候需要用到轮询便可凸显这种通信在某些场景的弊端,于是websocket
应运而生了。
WebSocket
他是为了解决客户端发起多个http
请求到服务器资源浏览器必须要经过长时间的轮训问题而生的,他实现了多路复用,他是全双工通信。在webSocke
t协议下客服端和浏览器可以同时发送信息。 建立了WebSocket
之后服务器不必在浏览器发送request
请求之后才能发送信息到浏览器。这时的服务器已有主动权想什么时候发就可以发送信息到服务器。而且信息当中不必在带有head的部分信息了与http
的长链接通信来说,这种方式,不仅能降低服务器的压力。而且信息当中也减少了部分多余的信息。
常常我们在自己开发一个东西是,写代码的时间是很少的,真正更多的时间是在思考,项目怎么做,用什么技术,如何组装等等,只要思考好这些问题,真正开写的时候就会很快了。
个人的习惯一直是把前后端分开来写,所以首先的想法是把项目分为前后端两端两个项目,前端选择了目前公司在使用的技术栈vue
,后端则是选择了每一个前端都能快速上手的node。同时由于相对于websocket
,我选择了封装更为完善的socket-io
。两者区别不大。大致来讲socket-io
是对websocket
的封装,但也不完全正确,Socket.io
将Websocket
和轮询(Polling)
机制以及其它的实时通信方式封装成了通用的接口,其日常使用大同小异。
vue
进行基本前端开发socket-io-client
替代websocket
进行双工通信vue-socket.io-extended
,对socket-io
在vue
的一个封装集成,方便在开发中更为方便使用node
框架nestjs
进行后端开发(因为之前都是用express
,koa
等开发个人项目,公司项目用hapi
,个人感觉,不同框架确实有不同的感受,express
,koa
这类框架官方并没有帮你强行约束你的开发,没有统一的规范,会由于不同人的开发爱好不大相同,而nest的定义是一个渐进式的Node.js框架,用于构建高效,可靠和可扩展的服务器端应用程序;不要问我为什么要放图,据说放图可以提高访问量。,所以也是来尝试使用了nestjs
来进行本次开发)mysql
nestjs
配套的typeorm
。(个人感觉typeorm
没有之前自己使用的sequelize
好用),当然,作为前端,本身对后端可能不是特别了解,这也是全凭个人喜好而定了。歌曲来源是通过爬虫获取xx音乐网站实现的
要想打造一个音乐聊天室
,浅而已见,需要两个东西,音乐
,聊天功能
,要想实现这两个功能,我们分个顺序,先实现聊天,在聊天的基础上再去实现音乐。
jsonwebtoken
但是这个的思路和我们日常的验证稍有差异我们日常使用前后端交互的时候都是会在请求头携带token
,而这个操作呢,我们一般是通过axios
请求拦截进行全局操作,那么我们对socket
如何操作呢,首先,我们依然离不开token
我们的校验最终还是要用它进行校验,所以就离不开登录,我们登录后拿到token
携带在socket
请求中,在前端项目中,我们一般只会维护一个socket
实例,我们来看看,初始化的时候需要哪些东西吧。
socketio官网 初始化的参数基本就是这样,这里的套件有什么用呢?其实就是当我们使用这个套件后,首先$socket
就挂载在了Vue
的原型上,其次,我们就可以在组件使用的时候,定义一个和methods
,data
同级下的sockets
,我们就可以和methods
一样,在下面定义所有socket-io
来自服务端的事件了,如果接触过wensocket
,我们知道,服务端与客户端是通过事件交流的,双方会触发不同的事件去告诉对方需要做什么,在这里有个问题,我们的token加在哪里,官方文档也没有找到具体的方法,首先我们知道,这里的token
并不能在axios
统一全局加,那么就需要我们自己去处理了。
首先,当我们使用socket
的时候,我们就要抛弃传统的http
方法,开始一个新的概念,在这里,是初始化的时候就会创建的,我们在初始化的时候,用户还没登录,又怎么会有token
呢,所以很明显,token
的注入时机一定是连接前,并且登陆后,所以初始化这里我们就可以跳过了,来到连接阶段。
频繁的让服务端去验证会消耗不必要的性能,前端首先判断,没有token
强制用户登录,之后才能去连接,如何连接呢?
我们在连接前把token放入this.$socket.client.io.opts.query
,也可以放入到请求头中,看个人需求,这两点都可以,我们只是为了在请求连接的过程中,携带上token,这时我们就可以控制传入的参数,当然除了token
你也可以携带更多的参数,看看有无必要,然后服务端就可以在request
的query
中拿到token
进行验证了。这样,我们就可以自由控制连接时机和参数了,服务端的校验和普通http
无差别,校验不通过拒绝连接即可。
在socket
中,我们无需每次请求都携带token
,我们只需要在连接的这一次携带即可,后续连接通过后,会生成一个固定的连接id,cliend.id
,这是双方连接的唯一凭证信息,也是通过这个和你进行通信的,那么我们的权限就到这里就完成了。
作为一个聊天室,最基本的功能就是聊天了,我们如何进行聊天呢,前面我们说到,socket
的通信实际就是响应各种事件,简单理解就是我们定义一些方法,会在双方发送事件的过程中触发,如何发送事件呢,客户端和服务端是稍有区别的
this.$socket.client.emit('CustomEvent', data)
这里便是像客户端发送一个事件,名字叫做CustomEvent
并且携带了data
数据,那么发送完这个请求后,服务端就会执行定义的CustomEvent
方法,同时接收到数据data。例如下图,接收到了一条消息服务端呢大体相同却又不同,为什么这么说呢,因为,在客户端,我们是一对一,我们的目标只有服务端,所以我们只能对服务端发送事件,而在服务端则不同,有多个客户端连接他,那么他就是多对一,他要为多人符文,所以,他面向的事件场景分为三类,
1. 像当前连接的一个客户端发送事件通知
1. 像除开当前连接用户的其他所有人发送消息
1. 像包含当前连接客户端的所有用户发送消息
很好理解,我们不可能所有消息都要通知给每个人,我们是需要分发给不同人消息的,有了这样一个概念,你就能快速理解了
一般而言呢,我们日常的聊天内容都会存在DB
项目的源码里面已经绑定了一个数据库了,这里我使用的是mysql
,这些都大同小异了,我们不需要过多关注,我们来大致分析一下一个用户发送消息后需要做哪些事情。
1. 当用户A连接进入房间的时候,首先我们要把房间的初始信息给与用户,一个基本的聊天室有哪些信息呢?
1. 历史用户聊天消息
2. 房间信息,房间公告,其他房间自定义设置
3. 当前所有在线用户列表,包含用户的一些基础信息,例如性别,签名等等
4. 歌曲信息,当前正在播放的歌曲,播放到多少秒了,从什么时候开始播放呢?【这些后面聊】
1. 用户进入房间后发送一条消息,服务端接收到消息,首先需要把消息存入`db`以便存储历史记录,然后把此条消息再通知给所有人,然后所有客户端会接收到有新消息来了的通知,就会吧新来的消息`push`进当前的消息列表,这样不论谁发消息,都只需要往数组加就好了。
1. 这就是一个聊天的基本流程
单纯的聊天当然不仅仅只有文字消息了,我们同样有表情,图片,或者微信中我们文字加小表情,如何实现呢,我们逐一分析
我们发现点击表情后变成了这种格式,其实如果你观察过以前的QQ
你会发现很多其实都是/大笑
类似这样的格式,他其实就是把图片的路径转为这样一个代键值,在发送出去的时候通过v-html
或者其他方式把他再编译为一个img
标签即可,这样就实现了这样的小表情和文字在一起的效果 ,发送出去如下
text文字类型
,img图片类型
,notice消息通知类型
,这样就言简意赅了,通过不同的类型渲染不同样式就轻松区分了,例如下图input
中有一个事件就是粘贴事件@paste
,在这其中e.target.file
就可以拿到粘贴的图片信息呢,然后通过文件上传接口把文件上传到远端,通过接口拿到一个返回的图片地址,把这个图片地址发给服务端就完成了自定义的图片信息费发送,那么视频呢,当然也是同理了,这样是不是清晰了呢。作为音乐聊天室,除了聊天,第二点当然是音乐功能了,对于h5
而言,h5
就是一个video
或者audio
,这点大家都知道就不用不说了,我们只需要src
引入资源地址就可以播放了,非常简单,但是我们当然不只是为了简单听歌了,我们想要实现一个人,所有人一起点歌,然后一起按顺序播放的功能,大家进入聊天室听到的都是一个相同时间的歌曲,对于这个功能,客户端只需要两件事情,
autopalay
也不会生效,需要和用户有交互才能播放,所以在进入房间前,有弹窗让用户确认,实现进入房间就会播放的功能。timespace
,用户进入房间之后,拿进入时间减去记录的时间戳就是歌曲播放时间,歌曲从这个时间播放就好了队列
,会按照顺序依次加入点歌用户的歌曲,这个时候,自动切歌就不会去数据库读取了,大致流程是,查看队列
有没有用户点的歌曲,没有在数据库随机
获取一个,有的话拿到队列第一首歌曲,然后切歌,再移除掉队列的歌曲,就实现了点歌自动播放了。issues
指出来吧抱着学习的态度去学习也许很慢、抱着兴趣的态度去学习就会事半功倍、把学习当做娱乐、打怪升级就会很有意思了、一个小小的个人项目分享给大家、不足的地方欢迎大家提出来、一起互相学习进步吧。