Vue3使用WebSocket实现实时消息推送 完整代码示例【教程】

畫卷琴夢

畫卷琴夢

2026-06-07

328人浏览

原创

不能直接在组件里 new websocket,因其原生 api 不自带重连、心跳、消息队列等容错能力,易导致静默断开、重复连接、invalidstateerror 等问题;必须封装为 usewebsocket composable,统一管理连接生命周期、状态监听、自动重连(带 cleartimeout 防堆积)、readystate 校验及 keepalive 场景适配。

vue3使用websocket实现实时消息推送 完整代码示例【教程】

WebSocket 连接不是“建了就完事”的东西——它极易因网络抖动、页面切换、服务端重启而断开,且原生 API 不自带重连、心跳、消息队列等能力。直接在 onMounted 里 new WebSocket 然后发消息,上线后大概率会遇到「消息收不到」「连接静默断开不重试」「重复连接」「send 报错 InvalidStateError」等问题。

为什么不能直接在组件里 new WebSocket?

原生 WebSocket 是低阶接口,暴露太多状态细节,却没封装常见容错逻辑:

  • readyState 变化需手动监听,但 onopen/onclose 触发时机与实际网络状态可能不同步
  • 断线后不会自动重连,onclosesetTimeout(connect, 3000) 容易失控(比如多次触发、未清定时器)
  • 组件卸载时若忘记 ws.close(),连接会残留;若卸载太快,ws 可能还没初始化完成
  • 多个组件共用同一连接时,无法共享 messages 或连接状态,造成重复实例

推荐用 useWebSocket 封装成可复用 Composable

把连接生命周期、消息收发、错误恢复都收进一个函数里,其他组件只管调用,不操心底层细节。下面是一个生产可用的简化版(基于 Composition API + TypeScript):

import { ref, onUnmounted, onDeactivated, onActivated } from 'vue'

export function useWebSocket(url: string) {
  const socket = ref<websocket null>(null)
  const messages = ref<any>([])
  const isConnected = ref(false)
  const reconnectTimer = ref<nodejs.timeout null>(null)

  const connect = () => {
    if (socket.value?.readyState === WebSocket.OPEN) return
    socket.value = new WebSocket(url)

    socket.value.onopen = () => {
      isConnected.value = true
      if (reconnectTimer.value) {
        clearTimeout(reconnectTimer.value)
        reconnectTimer.value = null
      }
      console.log('✅ WebSocket connected')
    }

    socket.value.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data)
        messages.value.push(data)
      } catch (e) {
        messages.value.push(event.data) // 非 JSON 消息也保留
      }
    }

    socket.value.onerror = (err) => {
      console.error('⚠️ WebSocket error:', err)
      isConnected.value = false
    }

    socket.value.onclose = () => {
      isConnected.value = false
      console.warn('❌ WebSocket closed, will retry in 3s')
      reconnectTimer.value = setTimeout(connect, 3000)
    }
  }

  const send = (data: any) => {
    if (socket.value?.readyState === WebSocket.OPEN) {
      socket.value.send(JSON.stringify(data))
    } else {
      console.warn('⚠️ WebSocket not ready, drop message:', data)
    }
  }

  const close = () => {
    socket.value?.close()
    if (reconnectTimer.value) {
      clearTimeout(reconnectTimer.value)
      reconnectTimer.value = null
    }
  }

  // 组件激活/失活时控制连接(用于 keep-alive 场景)
  onActivated(connect)
  onDeactivated(close)
  onUnmounted(close)

  connect() // 初始化连接

  return {
    isConnected,
    messages,
    send,
    close
  }
}
</nodejs.timeout></any></websocket>

注意几个关键点:

  • onActivated/onDeactivated 支持 <keepalive></keepalive> 场景,避免后台 tab 断连后不恢复
  • reconnectTimer 必须显式清除,否则组件反复挂载会堆积多个重连定时器
  • send 前检查 readyState,避免 InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state
  • onmessageJSON.parse 做了 try/catch,防止服务端发非 JSON 数据导致整个消息流中断

在组件中使用时别漏掉 onUnmounted 清理

即使用了 Composable,如果组件本身没正确响应销毁周期,仍可能泄漏连接。尤其在路由跳转或 v-if 切换频繁时:

WebSocket 8.18.2
WebSocket 8.18.2

WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。

下载
<script setup>
import { useWebSocket } from '@/composables/useWebSocket'

const { messages, send, close } = useWebSocket('ws://localhost:3000')

// ✅ 正确:Composable 内部已处理 onUnmounted
// ❌ 错误:再额外写 close() —— 会重复关闭,报错 "WebSocket is already in CLOSING or CLOSED state"

const handleSubmit = () => {
  send({ type: 'chat', content: 'hello' })
}
</script>

常见误操作:

  • 在组件内再次调用 close() —— Composable 已注册 onUnmounted,重复关会抛异常
  • useWebSocket 写在 onMounted 里 —— 失去响应式绑定,messages 不更新 UI
  • 传入的 url 是硬编码字符串,没走环境变量(如 import.meta.env.VITE_WS_URL),导致测试/生产地址不一致

服务端地址必须是 ws:// 或 wss://,且跨域要配好

浏览器强制校验协议和域名,常见错误:

  • Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss' → 检查 URL 是不是写了 http://
  • WebSocket connection to 'ws://localhost:3000' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED → 后端没启动,或端口被占
  • WebSocket connection to 'wss://xxx' failed: Error during WebSocket handshake: Unexpected response code: 403 → Nginx/反代没透传 UpgradeConnection header

如果是本地开发,确保后端已开启 WebSocket 服务,并允许前端域名(如 http://localhost:5173)跨源连接;生产环境务必用 wss://,且证书有效。

真正难的不是连上,而是连得稳、断得明、重得准、发得对——这些细节藏在每次 onclose 的判断里,藏在每个 send 前的 readyState 检查里,也藏在你有没有给 reconnectTimerclearTimeout 里。

前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

websocket vue3 vue3 websocket

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2362

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

717

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

2180

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

637

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1166

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

2085

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

2364

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

1474

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

498

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 2.2万人学习

Vue3.x 核心篇--十天技能课堂
Vue3.x 核心篇--十天技能课堂

共30课时 | 2.1万人学习

Vue3.x新特性篇--十天基础课堂
Vue3.x新特性篇--十天基础课堂

共20课时 | 1.5万人学习