網(wǎng)站首頁 編程語言 正文
后端:koa2+sequelize中使用websocket,可以使用的庫有ws
和koa-websocket
,此處使用ws
。
安裝ws
npm i --save ws
在koa2中使用ws
const Koa = require('koa')
const app = new Koa()
const WebSocket = require('ws')
const server = app.listen(8081)
wss = new WebSocket.Server({ server }) // 這樣可以實(shí)現(xiàn)websocket連接和http請求連接使用同一個端口
wss.on('connection', (ws) => {
ws.on('message', async message => {
console.log(`服務(wù)端接收到客戶端的消息:${message}`)
ws.send(`服務(wù)端說:${message}`) // 發(fā)送的消息需要是一個字符串
})
ws.on('close', () => {
console.log('客戶端關(guān)閉連接')
})
})
在Vue中使用WebSocket
const ws = new WebSocket('ws://localhost:8081')
ws.onopen = () => {
// 客戶端主動向服務(wù)端請求數(shù)據(jù)
console.log('連接成功')
ws.send('我是客戶端發(fā)送的消息')
}
ws.onmessage = (event) => {
// 這是從服務(wù)器接收到的消息
console.log(event.data) // 這是一個字符串
}
如何在ws連接中獲取信息,比如登錄用戶id
在客戶端建立websocket
連接時將查詢參數(shù)包含用戶id
const uid = 'ourworwo3292lmflkp'
const ws = new WebSocket(`ws://localhost:8081?uid=${uid}`)
在服務(wù)端的websocket
連接時處理請求url,拿到uid
const WebSocket = require('ws') // 需要安裝
const querystring = require('querystring') // 需要安裝
const url = require('url') // 不需要安裝
wss.on('connection', (ws, req) => {
const urlObj = url.parse(req.url)
const query = querystring.parse(urlObj.query) // 解析URL參數(shù)
const uid = query.uid
ws.on('message', async message => {
// ...
})
ws.on('close', () => {
// ...
})
})
如何實(shí)現(xiàn)ws連接通道獨(dú)立
方式1:比如可以使用uid為每個用戶建立單獨(dú)的連接通道
let cache = {}
wss.on('connection', (ws, req) => {
const urlObj = url.parse(req.url)
const query = querystring.parse(urlObj.query)
const uid = query.uid
cache[uid] = ws
cache[uid].on('message', async message => {
console.log(`服務(wù)端接收到客戶端的消息:${message}`)
cache[uid].send(`服務(wù)端說:${message}`)
})
cache[uid].on('close', () => {
console.log('客戶端關(guān)閉連接')
})
})
客戶端主動向服務(wù)端推送數(shù)據(jù)
const ws = new WebSocket(`ws://${base_url}`)
ws.onopen = () => {
// 客戶端主動向服務(wù)端請求數(shù)據(jù)
const msg = {
cmd: 'init',
type: 'log'
}
ws.send(JSON.stringify(msg))
}
服務(wù)端接收客戶端推送的數(shù)據(jù)
wss.on('connection', async (ws, req) => {
ws.on('message', async message => {
// console.log(`接收消息:${message}`)
try {
const clientMsg = JSON.parse(message)
if (clientMsg.type === 'log' && clientMsg.cmd === 'init') {
const msg = {
type: 'log',
data: ''
}
// 服務(wù)端主動向客戶端發(fā)送數(shù)據(jù)
ws.send(JSON.stringify(msg))
}
} catch (error) {
}
})
ws.on('close', () => {
console.log('客戶端關(guān)閉連接')
})
})
服務(wù)端的主動向客戶端推送數(shù)據(jù)
wss.on('connection', async (ws, req) => {
const msg = {
type: 'log',
data: ''
}
// 服務(wù)端主動向客戶端發(fā)送數(shù)據(jù)
ws.send(JSON.stringify(msg))
ws.on('close', () => {
console.log('客戶端關(guān)閉連接')
})
})
示例:定義一個日志表,記錄用戶登錄情況,使用ws連接后保證在日志表數(shù)據(jù)變化后服務(wù)端主動向客戶端推送數(shù)據(jù)
sequelize
中監(jiān)聽表的數(shù)據(jù)變化可以使用hook,比如afterCreate
、afterDestroy
、afterUpdate
、beforeCreate
、beforeDestroy
等
后端代碼示例:
const Log = require('../models/Log')
wss.on('connection', (ws) => {
ws.on('message', async message => {
try {
const clientMsg = JSON.parse(message)
if (clientMsg.type === 'log' && clientMsg.cmd === 'init') {
const msg = {
type: 'log', // 避免多個地方使用ws連接,定義一個類型作區(qū)別
data: '我是服務(wù)端定義的數(shù)據(jù)' // 這個地方可以處理需要向客戶端發(fā)送的ws數(shù)據(jù)
}
cache[uid].send(JSON.stringify(msg))
}
} catch (error) {
}
})
// 監(jiān)聽日志表新增數(shù)據(jù)后的生命周期
Log.addHook('afterCreate', async (log, options) => {
const msg = {
type: 'log',
data: '我是服務(wù)端定義的數(shù)據(jù)'
}
ws.send(JSON.stringify(msg))
})
// 監(jiān)聽日志表刪除數(shù)據(jù)后的生命周期
Log.addHook('afterDestroy', async (log, options) => {
const msg = {
type: 'log',
data: '我是服務(wù)端定義的數(shù)據(jù)'
}
ws.send(JSON.stringify(msg))
})
})
前端代碼示例:
const ws = new WebSocket('ws://localhost:8081')
ws.onopen = () => {
const msg = {
cmd: 'init',
type: 'log'
}
// 客戶端主動向服務(wù)端請求數(shù)據(jù)
ws.send(JSON.stringify(msg))
}
ws.onmessage = (event) => {
try {
// 客戶端接收服務(wù)端數(shù)據(jù)
const { data } = JSON.parse(event.data)
} catch (error) {
}
}
注意:后端代碼示例中的
afterDestroy
方法如果不能正確觸發(fā)的原因,需要檢查是否正確觸發(fā)destroy
方法(確保在數(shù)據(jù)庫中正確查詢到了要刪除的數(shù)據(jù),并且在查詢記錄的基礎(chǔ)上調(diào)用了destroy
方法)
示例:
const log= await Log.findByPk(logId)
if (log) {
await log.destroy()
}
如果使用Log.destroy()
不能正確觸發(fā)afterDestroy
方法
await Log.destroy({
where: {
id
}
})
websocket連接失敗和重連次數(shù)限制處理
連接次數(shù)是客戶端請求服務(wù)端ws連接的次數(shù),所以需要在客戶端即前端處理
let MAX_CONNECTION = 5 // 最大重連次數(shù)
let CONNECTED = 0 // 連接次數(shù)
let ws = null
getWebscoket() // 初始化websocket連接
function getWebscoket () {
ws = new WebSocket(`ws://${base_url}`) // 這里new之后指向了新的內(nèi)存地址,所以后續(xù)的open等事件都會重新監(jiān)聽,連接失敗后判斷重連次數(shù),需要保證ws的內(nèi)存地址指向一致
ws.onopen = () => {
// 客戶端主動向服務(wù)端請求數(shù)據(jù)
const msg = {
cmd: 'init',
type: 'log'
}
ws.send(JSON.stringify(msg))
}
ws.onmessage = (event) => {
try {
const { data } = JSON.parse(event.data)
weekData.value = data
} catch (error) {
ElMessage.error(error)
}
}
ws.onerror = (error) => {
// 連接錯誤操作
}
ws.onclose = () => {
// 連接關(guān)閉操作
reWsConnect()
if (CONNECTED >= MAX_CONNECTION) {
ElMessage.error('連接失?。嚎赡芎笈_未啟動')
}
}
}
// ws連接失敗后重新連接處理,連接次數(shù)限制處理
function reWsConnect () {
setTimeout(() => {
if (CONNECTED < MAX_CONNECTION) {
getWebscoket()
CONNECTED++
}
}, 2000)
}
原文鏈接:https://blog.csdn.net/qq_38157825/article/details/129971272
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2021-12-03 C++中signed?main和int?main的區(qū)別_C 語言
- 2022-04-10 微信小程序 base64 圖片 canvas 畫布 drawImage 實(shí)現(xiàn)
- 2023-12-23 React環(huán)境安裝配置
- 2022-08-23 多線程python的實(shí)現(xiàn)及多線程有序性_python
- 2023-10-16 使用elemnt移動端字體大小會自動變小
- 2023-01-05 Flutter?Widget之NavigationBar使用詳解_Android
- 2023-01-09 Redis排序命令Sort深入解析_Redis
- 2022-11-03 C#事件中的兩個參數(shù)詳解(object?sender,EventArgs?e)_C#教程
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支