【node进阶】深入浅出websocket即时通讯(二)-实现简易的群聊&私聊

✅ 作者简介:一名普通本科大三的学生,致力于提高前端开发能力

✨ 个人主页:前端小白在前进的主页

🔥 系列专栏 : node.js学习专栏

⭐️ 个人社区 : 个人交流社区

🍀 学习格言: ☀️ 打不倒你的会使你更强!☀️

💯 刷题网站:这段时间有许多的小伙伴在问有没有什么好的刷题网站,博主在这里给大家推荐一款刷题网站:👉点击访问牛客网👈牛客网支持多种编程语言的学习,各大互联网大厂面试真题,从基础到拔高,快来体验一下吧!


在这里插入图片描述


🔥前言

相信在上一篇的文章中大家对websocket的基本轮廓包括基础知识做了一定的了解学习,那么本篇文章将会从demo的角度去实现群聊和私聊的功能,一起来看看吧!

📃目录

  • 实现效果
  • 前台核心代码
    • 设置不同状态
    • 封装一个发送信息函数
  • 后台核心代码
    • 获取到token
    • 封装一个给前端返回消息的函数
    • 定义与前端一致的状态对象
    • 封装一个js文件处理token
    • 校验token
  • 前台实现(所有代码)
  • node后台实现(所有代码)
  • 小结

实现效果

在这里插入图片描述

这里有个小遗憾,我忘给私聊添加一个简单的样式了,这也是最后我突然发现了,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过期'))
    }

前台实现(所有代码)




    
    
    
    Document
    



    

欢迎来到聊天室

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 = `All` + onlineList.map(item => ` <option value="${item.username}">${item.username} `).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)) } }

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,相信大家会写一个登录的接口和简单页面!


👑书写不易,希望大家能够给予三连支持,期待我更好的文章哟👑


在这里插入图片描述

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/ddb2628d7b.html