项目已上传到Github
点击这里跳转到 Git Hub Websocket
首先引入koa、koa-router、koa-static等服务需要中间件,引入配置文件use中间件然后挂载静态服务处理,以及路由处理,在这里我是分模块引入了,具体看代码。
引入相应模块,并监听80端口。
这里可能会有一些疑问,这里的app.ws其实相当于总管,只要有一个用户进来我就在实例下创建一个服务线程,总管就多一个员工。每个服务线程会生成一个上下文,每个上下文主体其实是这个websocket,直接用ctx会报错,在第一次接收到信息时也就是第一次登录时会记录登录ID给这个对象,这样就可以不同用户享受同样的服务,只需要判断你想要的服务是什么。
app.ws.use((ctx, next) => {
/* 每打开一个连接就往 CTXS 添加一个上下文 */
ctxs.push(ctx);/*来一个我就管理一个 记录名单*/
ctx.websocket.on("message", (message) => {
var data = JSON.parse(message);//处理数据
// data.type = "msg";
if(data.user.type == "login"){//初始化员工ID
ctx.websocket.id = data.user.uid;
console.log("用户"+ data.user.uid +"加入聊天室");
}else if(data.type=="chat"){//聊天模式 分配对应数据
var need = {
send_time:data.send_time,
msg:data.user.send_msg,
type:'msg',
uname:data.user.uname,
uid:data.user.uid,
uimg: data.user.uimg
};
ctxs.forEach((s)=>{
/* 接收者 */
if(s.websocket.id==data.receiver.uid&&s.websocket.readyState==1){
s.websocket.send(JSON.stringify(need));
}
/* 发送者提示 */
if(s.websocket.id==data.user.uid&&s.websocket.readyState==1){
s.websocket.send(JSON.stringify({msg:"发送成功!",status:1,error:0,type:'tip'}));
}
if(s.websocket.id==data.user.uid&&s.websocket.readyState==3){
s.websocket.send(JSON.stringify({msg:"发送失败!",status:0,error:1,type:'tip'}));
}
})
}
});
ctx.websocket.on("close", (message) => {
/* 连接关闭时, 清理 上下文数组, 防止报错 */
let index = ctxs.indexOf(ctx);
console.log(ctxs[index].websocket.id+"关闭了链接")
ctxs.splice(index, 1);
});
});
有小伙伴会问了,这里为什么要循环呢?
这里循环是要找到员工也就是对应ID的websocket服务,然后员工对应前台登录的用户,因为这里是一对一聊天,当然服务也是一对一,这里举个栗子:
**逻辑:
我登录服务器——》服务器记录我的登录ID——》我找人聊天——》告诉服务器我找的人的ID、还有我要说的信息——》服务器帮我找到我要找的人———》帮我把信息发送给他。
var CreateWebSocket = (function () {
return function (urlValue) {
if (window.WebSocket) return new WebSocket(urlValue);
if (window.MozWebSocket) return new MozWebSocket(urlValue);
return false;
}
})();
/* 实例化 WebSocket 连接对象, 地址为 ws 协议 */
var webSocket = CreateWebSocket("ws://localhost");
前端发送消息主要步骤为:建立服务(此时为登录服务器,服务器会记录用户ID)——》获取输入信息、收信人ID、发送时间等——》保存本地聊天记录并更新视图——》通过Websocket发送信息——》服务器接受信息并处理。
ws_send: function () {
/* 发送消息 */
let odate = new Date();
send_time = odate.toLocaleString();
let alldata = JSON.stringify({
user: this.chat_user,//发送者 当前用户
receiver: this.chat_friend,//接收人 当前聊天的对象
send_time,//发送时间
type: 'chat'//类型
});
if (!this.chat_record.hasOwnProperty(this.chat_friend.uid)) this.chat_record[this
.chat_friend.uid] = [];
if (this.chat_friend.uid != this.chat_user.uid) {
// this.chat_record[this.chat_friend.uid].push()
this.$set(this.chat_record[this.chat_friend.uid], this.chat_record[this.chat_friend
.uid].length, {
send_time,
msg: this.chat_user.send_msg,
...this.chat_user
});
}
webSocket.send(alldata);
var ele = document.getElementById('recordList');
ele.scrollTop = ele.scrollHeight;
this.chat_user.send_msg = '';
},
前端接受消息主要步骤为:监听服务——》获取所有信息(服务器已处理信息)——》加入聊天记录——》更新视图。
rceiverMsg: function (data) {
let {
send_time,
msg,
uname,
uid,
uimg
} = {
...data
};
let id = uid + '';
if (!this.chat_record.hasOwnProperty(id)) this.chat_record[id] = [];
this.$set(this.chat_record[id], this.chat_record[id].length, {
send_time,
msg,
uname,
uid,
uimg
});
this.$forceUpdate();
},
具体的代码实现思路大概就是这些,websocket就相当于一个中间商帮你找到对应的用户,作为一个中间者传递消息。
我是工作一年多的前端工程师,喜欢关注一些前端全栈有趣的东西,目标是从前端走向全栈,后续工作之余还会更新一个群聊的Websocket,有兴趣的小伙伴可以关注我哟!
如果小伙伴看了我的文章由什么启发或者有什么疑惑的话都可以在下面评论或者私信我!