網站首頁 編程語言 正文
后端: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 }) // 這樣可以實現websocket連接和http請求連接使用同一個端口
wss.on('connection', (ws) => {
ws.on('message', async message => {
console.log(`服務端接收到客戶端的消息:${message}`)
ws.send(`服務端說:${message}`) // 發送的消息需要是一個字符串
})
ws.on('close', () => {
console.log('客戶端關閉連接')
})
})
在Vue中使用WebSocket
const ws = new WebSocket('ws://localhost:8081')
ws.onopen = () => {
// 客戶端主動向服務端請求數據
console.log('連接成功')
ws.send('我是客戶端發送的消息')
}
ws.onmessage = (event) => {
// 這是從服務器接收到的消息
console.log(event.data) // 這是一個字符串
}
如何在ws連接中獲取信息,比如登錄用戶id
在客戶端建立websocket
連接時將查詢參數包含用戶id
const uid = 'ourworwo3292lmflkp'
const ws = new WebSocket(`ws://localhost:8081?uid=${uid}`)
在服務端的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參數
const uid = query.uid
ws.on('message', async message => {
// ...
})
ws.on('close', () => {
// ...
})
})
如何實現ws連接通道獨立
方式1:比如可以使用uid為每個用戶建立單獨的連接通道
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(`服務端接收到客戶端的消息:${message}`)
cache[uid].send(`服務端說:${message}`)
})
cache[uid].on('close', () => {
console.log('客戶端關閉連接')
})
})
客戶端主動向服務端推送數據
const ws = new WebSocket(`ws://${base_url}`)
ws.onopen = () => {
// 客戶端主動向服務端請求數據
const msg = {
cmd: 'init',
type: 'log'
}
ws.send(JSON.stringify(msg))
}
服務端接收客戶端推送的數據
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: ''
}
// 服務端主動向客戶端發送數據
ws.send(JSON.stringify(msg))
}
} catch (error) {
}
})
ws.on('close', () => {
console.log('客戶端關閉連接')
})
})
服務端的主動向客戶端推送數據
wss.on('connection', async (ws, req) => {
const msg = {
type: 'log',
data: ''
}
// 服務端主動向客戶端發送數據
ws.send(JSON.stringify(msg))
ws.on('close', () => {
console.log('客戶端關閉連接')
})
})
示例:定義一個日志表,記錄用戶登錄情況,使用ws連接后保證在日志表數據變化后服務端主動向客戶端推送數據
sequelize
中監聽表的數據變化可以使用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連接,定義一個類型作區別
data: '我是服務端定義的數據' // 這個地方可以處理需要向客戶端發送的ws數據
}
cache[uid].send(JSON.stringify(msg))
}
} catch (error) {
}
})
// 監聽日志表新增數據后的生命周期
Log.addHook('afterCreate', async (log, options) => {
const msg = {
type: 'log',
data: '我是服務端定義的數據'
}
ws.send(JSON.stringify(msg))
})
// 監聽日志表刪除數據后的生命周期
Log.addHook('afterDestroy', async (log, options) => {
const msg = {
type: 'log',
data: '我是服務端定義的數據'
}
ws.send(JSON.stringify(msg))
})
})
前端代碼示例:
const ws = new WebSocket('ws://localhost:8081')
ws.onopen = () => {
const msg = {
cmd: 'init',
type: 'log'
}
// 客戶端主動向服務端請求數據
ws.send(JSON.stringify(msg))
}
ws.onmessage = (event) => {
try {
// 客戶端接收服務端數據
const { data } = JSON.parse(event.data)
} catch (error) {
}
}
注意:后端代碼示例中的
afterDestroy
方法如果不能正確觸發的原因,需要檢查是否正確觸發destroy
方法(確保在數據庫中正確查詢到了要刪除的數據,并且在查詢記錄的基礎上調用了destroy
方法)
示例:
const log= await Log.findByPk(logId)
if (log) {
await log.destroy()
}
如果使用Log.destroy()
不能正確觸發afterDestroy
方法
await Log.destroy({
where: {
id
}
})
websocket連接失敗和重連次數限制處理
連接次數是客戶端請求服務端ws連接的次數,所以需要在客戶端即前端處理
let MAX_CONNECTION = 5 // 最大重連次數
let CONNECTED = 0 // 連接次數
let ws = null
getWebscoket() // 初始化websocket連接
function getWebscoket () {
ws = new WebSocket(`ws://${base_url}`) // 這里new之后指向了新的內存地址,所以后續的open等事件都會重新監聽,連接失敗后判斷重連次數,需要保證ws的內存地址指向一致
ws.onopen = () => {
// 客戶端主動向服務端請求數據
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 = () => {
// 連接關閉操作
reWsConnect()
if (CONNECTED >= MAX_CONNECTION) {
ElMessage.error('連接失敗:可能后臺未啟動')
}
}
}
// ws連接失敗后重新連接處理,連接次數限制處理
function reWsConnect () {
setTimeout(() => {
if (CONNECTED < MAX_CONNECTION) {
getWebscoket()
CONNECTED++
}
}, 2000)
}
原文鏈接:https://blog.csdn.net/qq_38157825/article/details/129971272
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-03-21 windows設置開機自動運行批處理的方法_DOS/BAT
- 2022-04-15 SpringBoot系列之MongoDB?Aggregations用法詳解_MongoDB
- 2023-07-22 SpringBoot中@Cacheable如何使用
- 2022-06-04 sentinel支持的redis高可用集群配置詳解_Redis
- 2023-01-14 GoLang日志監控系統實現_Golang
- 2022-07-06 C語言深入探究水仙花數與變種水仙花數代碼_C 語言
- 2022-12-04 python中的list字符串元素排序_python
- 2022-12-06 nginx?pod?hook鉤子優雅關閉示例詳解_nginx
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支