vue3中使用websocket

目录

创建websocket服务端

创建websocket客户端

其他示例

websocket在线测试工具: 

WebSocket在线测试工具 (qianbo.com.cn)icon-default.png?t=N7T8https://www.qianbo.com.cn/Tool/WebSocket/WebSocket在线测试工具 (wstool.js.org)icon-default.png?t=N7T8http://wstool.js.org/WebSocket在线测试 - 您的超级在线工具 - https://www.tmdtool.comicon-default.png?t=N7T8http://websocket.tmdtool.com/

WebSocket是一种在Web应用程序中实现双向通信的通信协议,它允许客户端和服务器之间建立持久的、低延迟的连接,以实现实时数据传输。相比传统的HTTP请求,WebSocket更适合需要实时性和交互性的应用程序。

WebSocket解决了传统HTTP请求的一些限制,例如:

  • 实时性: 传统HTTP请求需要客户端定期轮询服务器以获取新数据,而WebSocket允许服务器主动推送数据给客户端,实现实时更新。
  • 双向通信: WebSocket支持双向通信,客户端和服务器都可以发送消息,而不是仅限于客户端向服务器发送请求。
  • 低延迟: WebSocket连接保持开放,减少了连接和断开的开销,从而实现更低的通信延迟。
  • 跨平台:WebSocket协议是一种标准化的协议,被广泛支持和应用于不同的平台和编程语言中

关于WebSocket通信的简单介绍:

  • 握手阶段:在建立WebSocket连接之前,客户端需要发送一个HTTP请求到服务器,请求升级为WebSocket协议。这个过程称为握手(Handshake)。如果服务器支持WebSocket协议,它将返回带有特定标头的HTTP响应,表示握手成功。
  • 建立连接:客户端收到服务器的握手响应后,会重新建立连接。此时,连接将从HTTP协议切换到WebSocket协议,并保持打开状态。这样就建立了可持续的双向通信通道。
  • 数据传输:一旦WebSocket连接建立,客户端和服务器可以开始互相发送消息。客户端和服务器都可以通过发送文本或二进制数据来通信。消息可以是简单的字符串,也可以是复杂的数据结构,如JSON对象等。
  • 断开连接:当需要关闭WebSocket连接时,客户端或服务器可以主动发送一个关闭帧来断开连接。收到关闭帧的一方会结束连接并发送回应帧,完成连接的关闭。

创建websocket服务端

新建文件夹a,并在a目录下生成package.json。执行以下命令即可:

npm init -y

  安装依赖包:

npm i koa ws

在package.json的同级目录下新建index.js文件:

const Koa = require('koa');
const WebSocket = require('ws');
const http = require('http');

const app = new Koa();
const server = http.createServer(app.callback());
const wss = new WebSocket.Server({ server });

const port = 3039;

wss.on('connection', (ws) => {
    console.log('WebSocket 连接已建立!');
    ws.on('message', (message) => {
        console.log(`收到消息:${message}`);

        // 向客户端发送消息
        setInterval(() => {
            ws.send(JSON.stringify({
                data: {
                    position: [104, 30, 100],
                    type: 1
                }
            }));
        }, 1000)
    });
});

server.listen(port, () => {
    console.log(`ws地址:ws://localhost:${port}`);
});

执行命令启动服务端:

node index.js

创建websocket客户端

新建html文件,内容如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test</title>
    <style>
        * {
            margin: 0;
            padding: 0
        }
    </style>
</head>

<body>
</body>
<script>
    const ws = new WebSocket('ws://localhost:3039');
    ws.onopen = () => {
        console.log('WebSocket 连接已建立!');
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ username: '张三', age: 33 }));
        } else {
            console.error('Websocket未连接');
        }
    };

    ws.onmessage = (event) => {
        console.log(`收到消息:${event.data}`);
    };

</script>

</html>

双击打开html文件,按F12查看控制台打印

可见连接成功!

在websocket在线工具中查看效果:WebSocket在线测试 - 您的超级在线工具 - https://www.tmdtool.comicon-default.png?t=N7T8http://websocket.tmdtool.com/

其他示例

示例1:

<template>
  <div></div>
</template>

<script>
export default {
  data() {
    return {
      websocket: null, // WebSocket对象
      reconnectInterval: 3000, // 重连间隔时间(毫秒)
      heartbeatInterval: null, // 心跳定时器
    };
  },
  created() {
    this.setupWebSocket(); // 创建WebSocket连接
  },
  methods: {
    setupWebSocket() {
      this.websocket = new WebSocket("ws链接地址"); // 创建WebSocket连接
      this.websocket.onopen = this.onWebSocketOpen; // WebSocket连接打开时的处理函数
      this.websocket.onmessage = this.onWebSocketMessage; // 收到WebSocket消息时的处理函数
      this.websocket.onclose = this.onWebSocketClose; // WebSocket连接关闭时的处理函数
    },
    closeWebSocket() {
      if (this.websocket) {
        this.websocket.close(); // 关闭WebSocket连接
      }
    },
    /**
     *  WebSocket连接打开后,启动心跳检测
     */
    onWebSocketOpen() {
      console.log("WebSocket connection is open");
      this.startHeartbeat();
      // 发送初始化消息
      const initMessage = {
        type: "sub",
        topic: "/aa/bb/cc/d",
        parameter: {},
        id: "bb",
      };
      this.sendMessage(JSON.stringify(initMessage));
    },
    // 处理从服务器接收的消息
    onWebSocketMessage(event) {
      if (event.data) {
        const message = JSON.parse(event.data);
        //    根据业务来处理数据
      }
    },
    onWebSocketClose() {
      console.log("WebSocket connection is closed");
      this.stopHeartbeat(); // WebSocket连接关闭时,停止心跳检测
      setTimeout(this.setupWebSocket, this.reconnectInterval); // 在一定时间后重连WebSocket
    },
    sendMessage(message) {
      if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
        this.websocket.send(message); // 发送消息到WebSocket服务器
      }
    },
    startHeartbeat() {
      this.heartbeatInterval = setInterval(() => {
        if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
          this.websocket.send("ping"); // 发送心跳消息
        }
      }, 10000); // 每10秒发送一次心跳
    },
    stopHeartbeat() {
      if (this.heartbeatInterval) {
        clearInterval(this.heartbeatInterval); // 停止心跳检测定时器
      }
    },
  },
  beforeDestroy() {
    this.closeWebSocket(); // 在组件销毁前关闭WebSocket连接
  },
};
</script>
<style lang="scss" scoped></style>

 示例2:

import { onUnmounted, ref } from 'vue'

import { useSystemStore } from '@/store/modules/systemStore/systemStore'

interface QueryType {
  url: string //url
  options?: OptionsType //配置
  params?: object //url参数
  onmessage?: Function //回调函数
}
interface OptionsType {
  maxReconnect?: number //最大重连次数, -1 标识无限重连
  interval?: number //心跳间隔
  timeout?: number //  响应超时时间
  pingMessage?: string // 心跳请求信息
}
const defaultOptions = {
  maxReconnect: 6,
  interval: 30 * 1000,
  timeout: 10 * 1000,
  pingMessage: 'ping'
}

/**
 * websocket封装
 * @param {object} param0
 * @returns  serverMessage, sendMessage, destroySocket
 */
export default function useWebSocket({ url, options = {}, params, onmessage }: QueryType) {
  const OPTION = { ...defaultOptions, ...options }
  let socket: WebSocket | null = null //websocket实例
  let pingTimeoutObj: NodeJS.Timeout | null = null //延时发送心跳的定时器
  let pongTimeoutObj: NodeJS.Timeout | null = null //接收心跳响应的定时器
  let reconnectCount: number = 0 // 重连尝试次数
  let lockReconnect: Boolean = false // 重连锁,避免多次重连

  const token = useSystemStore().getToken

  // 初始化连接socket
  function initWebSocket() {
    const VITE_APP_SOCKET_API = import.meta.env.VITE_APP_SOCKET_API
    const _params = objectToEncodeQuery(params)
    const wsUri = `${VITE_APP_SOCKET_API}${url}?token=${token}` + _params

    socket = new WebSocket(wsUri)

    // 连接成功
    socket.onopen = onOpen
    // 连接错误
    socket.onerror = onError
    // 接收信息
    socket.onmessage = onMessage
    // 连接关闭
    socket.onclose = onClose
  }

  /**
   * 连接成功事件
   */
  function onOpen() {
    // 开启心跳
    startHeartbeat()
    reconnectCount = 0
  }

  /**
   * 连接失败事件
   * @param e
   */
  function onError(e) {
    console.error(`WebSocket connection error:${e.code} ${e.reason} ${e.wasClean}`)
    reconnect()
  }

  /**
   * 连接关闭事件
   * @param e
   */
  function onClose() {
    reconnect()
  }

  /**
   * 重新连接
   */
  function reconnect() {
    if (!token) {
      return
    }

    if (lockReconnect || (OPTION.maxReconnect !== -1 && reconnectCount > OPTION.maxReconnect)) {
      return
    }

    lockReconnect = true
    setTimeout(() => {
      reconnectCount++
      // 建立新连接
      initWebSocket()
      lockReconnect = false
    }, 5000)
  }

  /**
   * 清空定时器
   */
  function clearTimeoutObj() {
    pingTimeoutObj && clearTimeout(pingTimeoutObj)
    pongTimeoutObj && clearTimeout(pongTimeoutObj)
  }

  /**
   * 开启心跳
   */
  function startHeartbeat() {
    console.log('startHeartbeat')
    // 清空定时器
    pingTimeoutObj && clearTimeout(pingTimeoutObj)
    // 延时发送下一次心跳
    pingTimeoutObj = setTimeout(() => {
      sendMessage(OPTION.pingMessage)
    }, OPTION.interval)
  }

  const serverMessage = ref()
  /**
   * 接收服务器推送的信息
   * @param msgEvent
   */
  function onMessage(msgEvent) {
    console.log('msgEvent')
    // 收到服务器信息,心跳重置并发送
    startHeartbeat()
    const text = msgEvent.data

    if (text === 'pong') {
      return
    }
    const data = JSON.parse(msgEvent.data)
    serverMessage.value = data.data
    onmessage && onmessage(data.data)
  }

  function sendMessage(message: string) {
    // 如果连接正常
    if (socket && socket.readyState === 1) {
      // 这里发送一个心跳,后端收到后,返回一个心跳消息,
      socket.send(message)
      // 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
      pongTimeoutObj && clearTimeout(pongTimeoutObj)
      pongTimeoutObj = setTimeout(() => {
        socket && socket.close()
      }, OPTION.timeout)
    } else {
      // 否则重连
      reconnect()
    }
  }
  /**
   * 销毁socket
   */
  function destroySocket() {
    if (socket) {
      lockReconnect = true
      socket.close()
      clearTimeoutObj()
    }
  }
  //  断开连接
  onUnmounted(() => {
    destroySocket()
  })

  /**
   * 对象转url参数
   */
  function objectToEncodeQuery(query: object | undefined): string {
    if (!query) return ''

    const params = Object.keys(query)
      .filter(key => query[key])
      .map(key => {
        return encodeURIComponent(key) + '=' + encodeURIComponent(query[key])
      })
      .join('&')

    return params
  }

  initWebSocket()

  return { serverMessage, sendMessage, destroySocket }
}

示例3:

// src/utils/websocket.ts
import { ref, onUnmounted } from 'vue';
 
interface WebSocketOptions {
    url: string;
    protocols?: string | string[];
    reconnectTimeout?: number;
}
 
class WebSocketService {
    private ws: WebSocket | null = null;
    private callbacks: { [key: string]: Function[] } = {};
    private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔
 
    constructor(private options: WebSocketOptions) {}
 
    public open(): void {
        this.ws = new WebSocket(this.options.url, this.options.protocols)
        this.ws.addEventListener('open', this.handleOpen);
        this.ws.addEventListener('message', this.handleMessage);
        this.ws.addEventListener('error', this.handleError);
        this.ws.addEventListener('close', this.handleClose);
    }
 
    public close(isActiveClose = false): void {
        if (this.ws) {
            this.ws.close();
            if (!isActiveClose) {
                setTimeout(() => this.reconnect(), this.reconnectTimeoutMs);
            }
        }
    }
 
    public reconnect(): void {
        this.open();
    }
 
    public on(event: 'message', callback: (data: any) => void): void;
    public on(event: 'open' | 'error' | 'close', callback: () => void): void;
    public on(event: string, callback: (...args: any[]) => void): void {
        if (!this.callbacks[event]) {
            this.callbacks[event] = [];
        }
        this.callbacks[event].push(callback);
    }
 
    private handleOpen = (): void => {
        console.log('WebSocket连接已建立');
        if (this.callbacks.open) {
            this.callbacks.open.forEach((cb) => cb());
        }
    };
 
    private handleMessage = (event: MessageEvent): void => {
        const data = JSON.parse(event.data);
        console.log('WebSocket接收到消息:', data);
        if (this.callbacks.message) {
            this.callbacks.message.forEach((cb) => cb(data));
        }
    };
 
    private handleError = (error: Event): void => {
        console.error('WebSocket错误:', error);
        if (this.callbacks.error) {
            this.callbacks.error.forEach((cb) => cb(error));
        }
    };
 
    private handleClose = (): void => {
        console.log('WebSocket连接已关闭');
        if (this.callbacks.close) {
            this.callbacks.close.forEach((cb) => cb());
            if (!this.options.reconnectTimeout) {
                this.reconnect();
            }
        }
    };
 
    public send(data: any): void {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(data));
        } else {
            console.warn('尝试发送消息时WebSocket未连接');
        }
    }
}
 
export default function useWebSocket(options: WebSocketOptions) {
    const wsService = new WebSocketService(options);
 
    onUnmounted(() => {
        wsService.close(true);
    });
 
    return {
        open: wsService.open.bind(wsService),
        close: wsService.close.bind(wsService),
        reconnect: wsService.reconnect.bind(wsService),
        on: wsService.on.bind(wsService),
        send: wsService.send.bind(wsService)
    };
import useWebSocket from '@/utils/websocket';//引入websocket.ts文件
 
import config from '@/config' //引入公共配置文件
 
const wsOptions = {
  url: config.wbBaseURL,
};
 
const { open, close, reconnect, on, send } = useWebSocket(wsOptions);
 
onMounted(() => {
  open();//在onMounted钩子中调用open函数,链接websocket
 
  // 注册消息接收处理函数
  on('message', (data) => {
    receivedMessage = data;
    console.log(data)
  });
});

示例4:参考基于Vue3封装一个好用的Websocket_vue3 websocket封装-CSDN博客文章浏览阅读1w次。通过封装Websocket类,我们可以在Vue3中轻松使用Websocket进行实时数据传输。希望本文能对大家有所帮助!_vue3 websocket封装https://blog.csdn.net/qq_27244301/article/details/130098672

示例5:参考vue3中使用webstocket_vue3 封装websocket.ts-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/irisMoon06/article/details/137522205 示例6:vue3 封装WebSocket(直接复制)_vue3 websocket封装-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/wsdshdhdhd/article/details/136008929

示例7:使用原生的 WebSocket API 在 Vue 3 中集成 WebSocket。_vue3集成websocket-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_35181466/article/details/137827004 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值