1_websocket工具封裝

pleaseAnswer發表於2024-06-11

Websocket

1 建構函式

  • new WebSocket(url[, protocols])

  • 引數

    • url:要連線到的 URL
    • protocols:單個協議字串或協議字串陣列

2 例項屬性

  • binaryType:接收的二進位制資料的型別

    • blob
    • arraybuffer
  • readyState:websocket 連線的當前狀態

readyState 值 mean 解釋
0 connecting 已建立 socket,連線尚未開啟
1 open 連線開啟且已做好通訊準備
2 closing 連線正在關閉
3 closed 連線已關閉

3 例項方法

  • close():關閉連線

    • close(code, reason)

    • 引數

      • code :指示關閉原因
        • 1000:正常關閉
        • 1001-1015:指示實際原因
  • send(data):傳送資料

4 事件

  1. close:websocket 連線關閉時觸發 close 事件

    • addEventListener("close", (event) => {});

    • onclose = (event) => {};

    • 屬性

      • code:伺服器傳送的關閉程式碼
      • reason:伺服器關閉連線的原因
      • wasClean:是否已完全關閉
  2. error:與 websocket 連線由於錯誤而關閉時觸發 error 事件

    • addEventListener("error", (event) => {});
    • onerror = (event) => {};
  3. message:websocket 接收到資料時觸發 message 事件

    • addEventListener("message", (event) => {});

    • onmessage = (event) => {};

    • 屬性

      • data
      • origin:訊息來源
  4. open:與 websocket 建立連線時觸發 open 事件

    • addEventListener("open", (event) => {});
    • onopen = (event) => {};
import { useState, useRef, useEffect } from 'react';

interface WebSocketOptions {
  url: string;
  onOpen?: () => void;
  onMessage?: (message: any) => void;
  onClose?: (event: Event) => void;
  onError?: (event: Event) => void;
  reconnectInterval?: number;
  reconnectAttrmpts?: number;
}

const defaultOptions: Required<WebSocketOptions> = {
  url: '', // 連線的長連線
  onOpen: () => {}, // 開啟連線
  onMessage: () => {}, // 訊息
  onClose: () => {}, // 關閉連線
  onError: () => {}, // 異常
  reconnectInterval: 1000, // 重連時長設定
  reconnectAttrmpts: Number.MAX_VALUE // 最大連線範圍數
};

const useWebsocket = (options: WebSocketOptions): [WebSocket | undefined, (message: any) => void, string, boolean] => {
  const { url, onOpen, onClose, onMessage, onError, reconnectInterval, reconnectAttrmpts } = {
    ...defaultOptions,
    ...options
  };

  const [isConnected, setIsConnected] = useState(false); // 是否連線
  const [reconnectCount, setReconnectCount] = useState(0); // 是否重連
  const [newMessage, setNewMessage] = useState(''); // 最新訊息

  const wsRef = useRef<WebSocket>();
  const reconnectTimerRef = useRef<NodeJS.Timer>();

  const connect = () => {
    setIsConnected(false);

    const ws = new WebSocket(url);

    // 與 websocket 建立連線時觸發
    ws.onopen = () => {
      console.log('----------websocket is connected---------');
      setIsConnected(true);
      setReconnectCount(0);
      onOpen();
    };

    // websocket 接收到資料時觸發
    ws.onmessage = event => {
      const message: any = JSON.parse(event.data);
      console.log(`----------websocket reveived message: ${message}--------------`);
      setNewMessage(event.data);
      onMessage(message);
    };

    // websocket 連線關閉時觸發
    ws.onclose = event => {
      console.error(`-----------wesocket closed with code ${event.code}-----------`);
      setIsConnected(false);
      onClose(event);

      // 是否重新連線
      // if (reconnectCount < reconnectAttrmpts) {
      //   reconnectTimerRef.current = setTimeout(() => {
      //     setReconnectCount(prevCount => prevCount + 1);
      //     connect();
      //   }, reconnectInterval);
      // }
    };

    // 與 websocket 連線由於錯誤而關閉時觸發
    ws.onerror = event => {
      console.error(`websocket error:`, event);
      onClose(event);
    };
    wsRef.current = ws;
  };

  useEffect(() => {
    connect();
    return () => {
      // 關閉連線
      wsRef.current?.close();
      clearTimeout(reconnectTimerRef.current);
    };
  }, []);

  const sendMessage = (message: any): void => {
    if (isConnected && wsRef.current) {
      console.log(`-------websocket sending message: ${JSON.stringify(message)}--------`);
      // 傳送資料
      wsRef.current.send(JSON.stringify(message));
    } else {
      console.error('cannot send message - websocket is not connected');
    }
  };

  return [wsRef.current, sendMessage, newMessage, isConnected];
};
export default useWebsocket;

相關文章