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

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

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 }) // 這樣可以實(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

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