日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

koa2+sequelize中websocket的使用

作者:前端開心果 更新時間: 2023-07-29 編程語言

后端:koa2+sequelize中使用websocket,可以使用的庫有wskoa-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,比如afterCreateafterDestroyafterUpdatebeforeCreatebeforeDestroy
在這里插入圖片描述
后端代碼示例:

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

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新