websocket.js的封装,包含保活机制,通用

计光赫
2023-12-01
const MODE = import.meta.env.MODE;
const hostname = MODE === 'production' ? 'xxx' : 'xxx';
const socketUrl = 'wss://' + hostname + '/ws';

class MyWebSocket {
    constructor(props) {
        this.props = props;
        this.connect();
        this.status = '';
        this.pingPong = 'ping';
        this.pingInterval = '';
        this.pongInterval = '';
    }

    // 连接websocket
    connect() {
        const that = this;
        this.ws = new WebSocket(socketUrl)
        this.ws.onopen = function () {
            console.log('WebScoket 连接成功!');
            that.status = 'open';

            const params = {
                action: 'auth',
                token: window.localStorage.getItem('token') || ''
            }

            if (that.ws && that.ws.readyState === 1) {
                that.ws.send(JSON.stringify(params));
            }

            that.ceartCheck();
            that.getMessage();
        }
    }

    // 保活测试
    ceartCheck() {
        this.pingInterval = setInterval(() => {
            if (this.ws.readyState === 1) {
                this.ws.send(JSON.stringify({ action: 'heartbeat' }));
            }
        }, 30000); // 30s 客户端发送一次心跳包

        this.pongInterval = setInterval(() => {
            if (this.pingPong === 'ping') {
                this.closeHandle('pingPong没有改变为pong');
            }
            this.pingPong = 'ping';
        }, 60000); // 60s检测一次服务端是否返回10203
    }

    // 重连
    closeHandle(err) {
        if (this.status !== 'close') {
            console.log(`断开,重连websocket:`, err);
            if (this.pingInterval !== undefined && this.pongInterval !== undefined) {
                // 清除定时器
                clearInterval(this.pingInterval);
                clearInterval(this.pongInterval);
            }
            this.connect(); // 重连
        } else {
            console.log(`websocket手动关闭!`);
        }
    }

    // 服务端信息推送
    getMessage() {
        this.ws.onmessage = e => {
            const data = JSON.parse(e.data);
            if (data.code === 10201) {
                console.log('认证成功:' + data.code);
            } else if (data.code === 10202) {
                console.log('心跳包发送成功:' + data.code);
            } else if (data.code === 10200) {
                console.log("推送消息啦: " + e.data);
                this.props.callback(data);
            } else if (data.code === 10203) { // 后端定时返回,以便确定是否断开连接
                this.pingPong = 'pong'
            } else {
                console.log("报错啦: " + data);
            }
        };
    }

    // 手动关闭连接
    close() {
        clearInterval(this.pingInterval);
        clearInterval(this.pongInterval);
        this.status = 'close';
        this.ws.close();
        console.log('WebSocket Close!!');
    }
}

export default MyWebSocket;
import MyWebSocket from '@/utils/webSocket';

let ws: any = null;
  useEffect(() => {
    if (window.localStorage.getItem('token')) {
      ws = new MyWebSocket({
        callback: (res) => {
          console.log('消息内容:', res);
          if (res.data.msg_type === 'order_declaration_boss_confirm_timeout') {
            notification.open({
              message: 'xxx',
              description: 'xxx',
              duration: 0,
              btn: <Button type="primary" size="small" onClick={() => {
                notification.destroy();
                navigate('/xxx')
              }}>查看超时工单</Button>,
              icon: <InfoCircleOutlined style={{ color: '#108ee9' }} />,
            });
          }
        }
      });
      return () => {
        ws?.close();
      }
    }
  }, [window.localStorage.getItem('token')])
 类似资料: