icxiaoyanz

icxiaoyanz

x

WebSocket 通信を Http のように簡単にする

前些天因为一个需求,必须要改用 WebSocket 进行通讯(为了绕开浏览器跨域限制),但是前面使用的接口都是用 Http 的。

心里正想着可能要大改动了……

哎嘿,怎么着,我看着之前写好的一个个请求调用方法:传参,await 等待,返回数据。

WebSocket 不也是得这样吗?发送数据,返回数据。只要把 WebSocket 的 send 方法套一个函数,然后 Promise 化,就可以像 Http 一样使用了。

実装#

実装も簡単で、ここでは @vueuse/coreuseWebSocket を使ってラップしています。

import { useWebSocket } from '@vueuse/core'
import { toast } from 'vue-sonner'

interface WebSocketHandler {
  resolve: (data: any) => void
  reject: (data: any) => void
}

const messageHandlers = new Map<string, WebSocketHandler>()

const ws = useWebSocket(
  'ws://localhost:10000/ws',
  {
    autoReconnect: {
      delay: 2000,
      retries: 3,
    },
    heartbeat: {
      interval: 30000,
      pongTimeout: 3000,
      responseMessage: 'pong',
    },
    onMessage: (_, event) => {
      if (!event.data.startsWith('{"id"')) return
      
      const response = JSON.parse(event.data)
      const handler = messageHandlers.get(response.id)
      if (!handler) return

      const isSuccess = response.code === 200
      if (isSuccess) handler.resolve(response.data)
      else {
        toast.warning(response.message)
        handler.reject(new Error(response.message))
      }
    }
  }
)

export function wsFetch<T>(params: T) {
  return new Promise<T>((resolve, reject) => {
    if (ws.status.value !== 'OPEN') {
      reject(new Error('WebSocket は接続されていません'))
      return
    }

    const id = getRequestId()

    ws.send(JSON.stringify({ ...params, id }))
    messageHandlers.set(id, { resolve, reject })
  })
}

function getRequestId() {
  return Date.now().toString() + Math.random().toString(36).slice(2, 9)
}

ここでは実際に Promise の resolvereject コールバックを保存しておき、情報を受け取った後に取り出して呼び出しています。

(完)

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。