基于Vue3实现WebSocket前后端双向通信

98 阅读4分钟

本文介绍了在 Vue3 中使用 WebSocket 实现即时通讯的基础功能:

  1. 封装了可复用的 WebSocket 服务
  2. 实现了消息的发送和接收
  3. 提供了简单的 WebSocket 测试服务器
  4. 列出了可能的扩展方向

这个基础实现可以满足简单的实时通讯需求,根据项目需求可以在此基础上进行扩展。

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,非常适合实现实时通讯功能。本文将介绍如何在 Vue3 项目中实现基础的 WebSocket 连接和消息收发功能。

第1步:封装WebSocket组合式函数

首先我们创建一个可复用的 WebSocket 组合式函数,封装连接、发送和接收消息的逻辑,方便复用。

// src/hooks/websocket.js  
import { ref } from 'vue'  
  
/**  
 * WebSocket 服务封装  
 * @param {string} url WebSocket 服务器地址  
 * @returns {Object} 包含连接、发送、接收等方法  
 */  
export function useWebSocket(url) {  
  // 存储 WebSocket 实例  
  const socket = ref(null)  
  // 存储接收到的消息  
  const messages = ref([])  
  // 连接状态  
  const isConnected = ref(false)
  
  /**  
   * 连接 WebSocket 服务器  
   */  
  const connect = () => {  
    return new Promise((resolve, reject) => {  
      // 创建 WebSocket 连接  
      socket.value = new WebSocket(url)  
  
      // 连接成功回调  
      socket.value.onopen = () => {  
        isConnected.value = true  
        console.log('WebSocket connected')  
        resolve()  
      }  
  
      // 接收消息回调  
      socket.value.onmessage = (event) => {  
        // 将接收到的消息存入 messages 数组  
        const message = JSON.parse(event.data)  
        messages.value.push(message)  
      }  
  
      // 错误处理  
      socket.value.onerror = (error) => {  
        console.error('WebSocket error:', error)  
        reject(error)  
      }  
  
      // 连接关闭回调  
      socket.value.onclose = () => {  
        isConnected.value = false  
        console.log('WebSocket disconnected')  
      }  
    })  
  }  
  
  /**  
   * 发送消息  
   * @param {Object} message 要发送的消息对象  
   */  
  const send = (message) => {  
    if (socket.value && isConnected.value) {  
      messages.value.push(message)//这里我将客户端发送的消息也推入消息队列  
      socket.value.send(JSON.stringify(message))  
    } else {  
      console.error('WebSocket is not connected')  
    }  
  }  
  
  /**  
   * 断开连接  
   */  
  const disconnect = () => {  
    if (socket.value) {  
      socket.value.close()  
    }  
  }  
  
  return {  
    socket,  
    messages,  
    isConnected,  
    connect,  
    send,  
    disconnect  
  }  
}

第2步:实现消息收发界面组件

接下来我们创建一个聊天组件,引入上面封装的 WebSocket 组合式函数
(当然WebSocket不止可以用来做聊天软件,凡是前后端双向通信的界面都可以这样用,所以下面的代码我隐藏了模板和样式)。

<!-- src/components/WebSocketDemo.vue -->  
<script setup>  
import { ref, onMounted, onUnmounted } from 'vue'  
import { useWebSocket } from '@/hooks/useWebsockHook.js'  
  
// 消息输入框  
const newMessage = ref('')  
  
// 初始化 WebSocket 连接  
const { connect, send, messages, isConnected, disconnect } = useWebSocket('ws://localhost:8080')  
  
// 组件挂载时连接 WebSocket  
onMounted(() => {  
  connect().catch(err => {  
    console.error('Failed to connect:', err)  
  })  
})  
  
// 组件卸载时断开连接  
onUnmounted(() => {  
  disconnect()  
})  
  
/**  
 * 发送消息  
 */  
const handleSend = () => {  
  if (newMessage.value.trim()) {  
    // 构造消息对象  
    const message = {  
      type'from_client'// 消息类型  
      content: newMessage.value// 消息内容  
      timestampDate.now() // 时间戳  
    }  
      
    // 发送消息  
    send(message)  
      
    // 清空输入框  
    newMessage.value = ''  
  }  
}  
</script>  
  
<template>  
  <div class="chat-container">  
    根据具体业务实现自己的模板  
  </div>  
</template>  
  
<style scoped>  
</style>

第3步:测试 WebSocket 服务器(实际开发中,由后端提供)

为了测试我们的前端代码是否可以正常地运行,本例基于 Node.js 实现 WebSocket 服务器

// server.js  
const WebSocket = require('ws')  
  
// 创建 WebSocket 服务器,监听 8080 端口  
const wss = new WebSocket.Server({ port8080 })  
  
wss.on('connection'(ws) => {  
  console.log('New client connected')  
   
  // 收到客户端消息时回调  
  ws.on('message'(message) => {  
    console.log('Received:', message.toString())  
     
    // 简单回声处理:将收到的消息原样返回  
    wss.clients.forEach(client => {  
      if (client.readyState === WebSocket.OPEN) {  
        const msgObj = JSON.parse(message.toString())  
        msgObj.type = 'from_server'  
        msgObj.content = `我已收到消息:< ${msgObj.content} > 一切正常哦!`  
        client.send(JSON.stringify(msgObj))  
      }  
    })  
  })  
   
  ws.on('close'() => {  
    console.log('Client disconnected')  
  })  
})  
  
console.log('WebSocket server running on ws://localhost:8080')

启动服务:

node server.js

实现效果

image.png

注意事项

  1. 报错:Error: Cannot find module 'ws'
    是因为项目缺少 WebSocket 服务器所需的 ws 依赖包。需要进入项目目录, 安装 ws 模块 npm install ws

  2. 发送消息,报错:WebSocket is not connected
    说明连接尚未建立或已断开
    注意端口,本例中的vite开发服务器默认端口是5173,不代表WebSocket服务器端口也是5173,他们是两个不同的服务,必须使用两个不同的端口

  3. 每次更改了服务都需要重新运行,没有运行代码变更就不会生效 image.png

补充:优化方向

本文只实现了基础功能,实际业务场景中还需要补充更多业务逻辑来保证可靠的服务

  1. 认证机制:添加 JWT 认证,确保连接安全
  2. 断线重连:自动重连机制,提高稳定性
  3. 心跳检测:保持连接活跃,检测断线
  4. 消息类型:区分系统消息、用户消息等
  5. 用户列表:显示用户状态
  6. 消息持久化:存储聊天记录到数据库
  7. 多房间/频道:支持不同的聊天房间
  8. ...