【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()生成tokengenerate(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屬性,目的是讓我們明確是誰進入到了聊天室,返回進入聊天室這個人的信息!
// 校驗tokenconst 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")// 校驗tokenconst 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,相信大家會寫一個登錄的接口和簡單頁面!
👑書寫不易,希望大家能夠給予三連支持,期待我更好的文章喲👑
總結
以上是生活随笔為你收集整理的【node进阶】深入浅出websocket即时通讯(二)-实现简易的群聊私聊的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: UVA11210 Chinese Mah
- 下一篇: 并发编程面试专题
