【node进阶】深入浅出websocket即时通讯(二)-实现简易的群聊&私聊
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
✅ 作者简介一名普通本科大三的学生致力于提高前端开发能力
✨ 个人主页前端小白在前进的主页
系列专栏 node.js学习专栏
⭐️ 个人社区 : 个人交流社区
学习格言: ☀️ 打不倒你的会使你更强☀️
刷题网站这段时间有许多的小伙伴在问有没有什么好的刷题网站博主在这里给大家推荐一款刷题网站:点击访问牛客网牛客网支持多种编程语言的学习各大互联网大厂面试真题从基础到拔高快来体验一下吧
前言
相信在上一篇的文章中大家对websocket的基本轮廓包括基础知识做了一定的了解学习那么本篇文章将会从demo的角度去实现
群聊
和私聊
的功能,一起来看看吧
目录
实现效果
这里有个小遗憾我忘给私聊添加一个简单的样式了这也是最后我突然发现了xdm你们在下面可以去添加一下私聊的简单dom我这里就用控制台打印实现了
前台核心代码
设置不同状态
在这里设置了四种状态每种状态对应着相应的功能有获取群列表信息
、转到群聊
、转到私聊
const WebSocketType = {
Error: 0, //错误
GroupList: 1,//群列表
GroupChat: 2,//群聊
SingleChat: 3//私聊
}
封装一个发送信息函数
因为我们给后端发送信息时只能传字符串
所以我们将传给后端的这个对象转换成字符串的形式使用内置方法JSON.stringify()
function createMessage(type, data, to) {
return JSON.stringify({
type,
data,
to
});
}
后台核心代码
获取到token
使用js中的内置方法new URL()
获取到请求地址的参数注意这里的req.url
是请求地址后面的参数
const myURL = new URL(req.url, "http://127.0.0.1:3000")
const token = myURL.searchParams.get("token")
封装一个给前端返回消息的函数
与前台的代码相似给前台对应的状态返回信息
function createMessage(type, user, data) {
return JSON.stringify({
type: type,
user: user,
data: data
});
}
定义与前端一致的状态对象
实现与前台对象相对应的状态
const WebSocketType = {
Error: 0, //错误
GroupList: 1, //群列表
GroupChat: 2, //群聊
SingleChat: 3 //私聊
}
封装一个js文件处理token
const jwt = require('jsonwebtoken')
const secret = 'ccc-data'
const JWT = {
//jwt的sign()生成token
generate(value,expires) {
return jwt.sign(value,secret,{expiresIn:expires})
},
//解密token验证
verify(token) {
try {
return jwt.verify(token,secret)
} catch (error) {
return false
}
}
}
module.exports = JWT
校验token
这里校验token成功后就会给前台返回欢迎来到本聊天室
的字样,并且给我们的句柄
添加一个user属性目的是让我们明确是谁进入到了聊天室返回进入聊天室这个人的信息
// 校验token
const payload = JWT.verify(token)
if (payload) {
ws.send(createMessage(WebSocketType.GroupChat, null, '欢迎来到本聊天室'));
ws.user = payload
//群发
sendAll()
} else {
ws.send(createMessage(WebSocketType.Error, null, 'token过期'))
}
前台实现(所有代码)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./stylesheets/chat.css">
</head>
<body>
<h1 id="h1">欢迎来到聊天室</h1>
<h3 id="h3"></h3>
<input type="text" id="text"><button id="send">send</button>
<select id="select"></select>
<div id="chat"></div>
<!-- 建立socket连接带着token后端验证 -->
<script>
h1.innerHTML = `${localStorage.getItem("username")}欢迎您来到聊天室`
const WebSocketType = {
Error: 0, //错误
GroupList: 1,//群列表
GroupChat: 2,//群聊
SingleChat: 3//私聊
}
function createMessage(type, data, to) {
return JSON.stringify({
type,
data,
to
});
}
const ws = new WebSocket(`ws://localhost:8080?token=${localStorage.getItem("token")}`)
ws.onopen = () => {
console.log('连接成功!');
}
ws.onmessage = (msgObj) => {
// console.log(msgObj.data);
msgObj = JSON.parse(msgObj.data)
switch (msgObj.type) {
case WebSocketType.Error:
localStorage.removeItem("token")
location.href = '/login'
break;
case WebSocketType.GroupList:
console.log(JSON.parse(msgObj.data));
const onlineList = JSON.parse(msgObj.data)
h3.innerHTML = ``
h3.innerHTML = `当前在线人数:${onlineList.length}`
select.innerHTML = ``
select.innerHTML = `<option value="all">All</option>` + onlineList.map(item => `
<option value="${item.username}">${item.username}</option>
`).join('')
break;
case WebSocketType.GroupChat:
console.log((msgObj.user ? msgObj.user.username : '广播') + ':' + msgObj.data);
var para = document.createElement("p");
var node = document.createTextNode((msgObj.user ? msgObj.user.username : '广播') + ':' + msgObj.data);
para.appendChild(node);
chat.appendChild(para);
break;
case WebSocketType.SingleChat:
console.log(msgObj.user.username + ':' + msgObj.data);
break;
}
}
send.onclick = () => {
if (select.value === 'all') {
// console.log('群发');
ws.send(createMessage(WebSocketType.GroupChat, text.value))
} else {
// console.log('私聊');
ws.send(createMessage(WebSocketType.SingleChat, text.value, select.value))
}
}
</script>
</body>
</html>
node后台实现(所有代码)
//websocket响应
const { json } = require('express');
const WebSocket = require('ws');
const JWT = require('../util/jwt');
const WebSocketServer = WebSocket.WebSocketServer
const wss = new WebSocketServer({
port: 8080
});
wss.on('connection', function connection(ws, req) {
const myURL = new URL(req.url, "http://127.0.0.1:3000")
console.log(req.url);
//获取到token随后进行验证
const token = myURL.searchParams.get("token")
// 校验token
const payload = JWT.verify(token)
console.log(payload);
if (payload) {
ws.send(createMessage(WebSocketType.GroupChat, null, '欢迎来到本聊天室'));
ws.user = payload
//群发
sendAll()
} else {
ws.send(createMessage(WebSocketType.Error, null, 'token过期'))
}
ws.on('message', function message(data) {
console.log('received: %s', data);
const msgObj = JSON.parse(data) //解析前台传来的数据
switch (msgObj.type) { //通过switch分支来进行不同状态的相应操作
case WebSocketType.GroupList: //获取进入聊天室的人员列表
ws.send(createMessage(WebSocketType.GroupList, null, JSON.stringify(Array.from(wss.clients).map(item => item.user))))
//由于返回的类型是set集合所以我们通过Array.from()转化为真正的数组
break;
case WebSocketType.GroupChat: //群聊分支
//转发给其他人
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(createMessage(WebSocketType.GroupChat, ws.user,msgObj.data),{binary : false})
}
});
break;
case WebSocketType.SingleChat: //私聊分支
wss.clients.forEach(function each(client) {
// console.log(client.user);
console.log(ws.user);
if (client.user.username === msgObj.to && client.readyState === WebSocket.OPEN) {
client.send(createMessage(WebSocketType.SingleChat, ws.user,msgObj.data),{binary : false})
}
});
break;
}
});
ws.on('close', () => {
wss.clients.delete(ws.user)
sendAll()
})
});
const WebSocketType = {
Error: 0, //错误
GroupList: 1, //群列表
GroupChat: 2, //群聊
SingleChat: 3 //私聊
}
function createMessage(type, user, data) {
return JSON.stringify({
type: type,
user: user,
data: data
});
}
const sendAll = () => {
//转发给其他人
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(createMessage(WebSocketType.GroupList, null, JSON.stringify(Array.from(wss.clients).map(item => item.user))))
}
});
}
小结
这些代码看起来觉得好多好多呀其实我们滤清思路分析一下可以发现前后端是对应着的按着对应关系一一去写代码就会非常轻松这里的代码逻辑相对来说还是很清晰的本篇文章到这里就结束了下周开始不定时要进行js的重生之路了
将会结合许许多多的demo带领大家去学习js不至于到头来啥也不会少年继续加油吧
注意登录
功能的设置token以及axios的拦截器将会在以后的node项目实战中与大家见面我们之前学了jwt相信大家会写一个登录的接口和简单页面
书写不易希望大家能够给予三连支持期待我更好的文章哟
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |