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

Posted 前端小白在前进

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了node进阶深入浅出websocket即时通讯-实现简易的群聊&私聊相关的知识,希望对你有一定的参考价值。

✅ 作者简介:一名普通本科大三的学生,致力于提高前端开发能力
✨ 个人主页:前端小白在前进的主页
🔥 系列专栏 : 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,相信大家会写一个登录的接口和简单页面!


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


Socket.IO介绍:支持WebSocket用于WEB端的即时通讯的框架

一、基本介绍

  WebSocket是HTML5的一种新通信协议,它实现了浏览器与服务器之间的双向通讯。而Socket.IO是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架,它包括了客户端的JavaScript和服务器端的Node.js。

  Socket.IO除了支持WebSocket通讯协议外,还支持许多种轮询(Polling)机制以及其它实时通信方式,并封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码。Socket.IO实现的Polling通信机制包括Adobe Flash Socket、AJAX长轮询、AJAX multipart streaming、持久Iframe、JSONP轮询等。Socket.IO能够根据浏览器对通讯机制的支持情况自动地选择最佳的方式来实现网络实时应用。当前,Socket.IO最新版本是于2015年1月19日发布的1.3.0版本,该版本增强了稳定性和提高了性能,并修复了大量Bug。

  Socket.IO设计的目标是构建能够在不同浏览器和移动设备上良好运行的实时应用,如实时分析系统、二进制流数据处理应用、在线聊天室、在线客服系统、评论系统、WebIM等。目前,Socket.IO已经支持主流PC浏览器(如IE、Safari、Chrome、Firefox、Opera等)和移动平台上的浏览器(iOS平台下的Safari、Android平台下的基于Webkit的浏览器等)。

  Socket.IO已经具有众多强大功能的模块和扩展API,如(session.socket.io)(http session中间件,进行session相关操作)、socket.io-cookie(cookie解析中间件)、session-web-sockets(以安全的方式传递Session)、socket-logger(JSON格式的记录日志工具)、websocket.MQ(可靠的消息队列)、socket.io-mongo(使用MongoDB的适配器)、socket.io-redis(Redis的适配器)、socket.io-parser(服务端和客户端通讯的默认协议实现模块)等。

  Socket.IO实现了实时、双向、基于事件的通讯机制,它解决了实时的通信问题,并统一了服务端与客户端的编程方式。启动了Socket以后,就像建立了一条客户端与服务端的管道,两边可以互通有无。它还能够和Express.js提供的传统请求方式很好的结合,即可以在同一个域名,同一个端口提供两种连接方式。

二、简单示例

   搭建Socket.IO环境需要先创建一个作为工作空间的目录,然后安装Node.js,并在工作空间下安装Socket.IO(命令:npm install socket.io),这样环境已经搭建完成。还可以安装基于Node.js框架(如Express.js等)以协助应用的服务器端开发。

  服务器段示例代码如下:

var io = require(\'socket.io\').listen(8080);
io.sockets.on(\'connection\', function (socket) {
    socket.emit(\'news\', { hello: \'world\' });
    socket.on(\'my other event\', function (data) {
        console.log(data);
    });
});

  客户端示例代码如下:

<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.dev.js"></script>
<script type="text/javascript">
var socket = io.connect(\'http://localhost:8080\');
socket.on(\'news\', function (data) {
    console.log(data); 
    socket.emit(\'my other event\', { my: \'data\' });
});
</script>

  执行之后:先客户端接受服务器推送信息news,打印{hello:world}

  后客户端向服务端发送信息,触发服务端事件,打印{ my: \'data\' }

以上是关于node进阶深入浅出websocket即时通讯-实现简易的群聊&私聊的主要内容,如果未能解决你的问题,请参考以下文章

Socket.IO介绍:支持WebSocket用于WEB端的即时通讯的框架

用于WEB端的即时通讯的框架Socket.IO

node+小程序+web端简单的websocket通讯

un-iapp配合Node.js使用wss在微信小程序实现socket即时通讯

websocket即时通讯

谈下WebSocket介绍,与Socket的区别