Nuxt 3 中直接在客户端用 new WebSocket() 可行但易失败,关键在于连接地址需为相对路径(如 /ws),代理配置必须启用 ws: true 并设置 Upgrade 头,服务端需通过 server/routes/ws.ts 拦截握手请求,多实例部署须配合 Nginx ip_hash 或 Redis PUB/SUB 保证消息一致性。

直接在 Nuxt 3 客户端页面里用 new WebSocket() 是可行的,但多数线上项目会失败——不是代码写错了,而是被代理层或服务端架构拦住了。关键不在“怎么连”,而在“连到哪儿”和“怎么让连接不被断掉”。
WebSocket 连接地址不能写死在客户端
开发时你可能习惯写 ws://localhost:8080/ws,但部署后这个地址会失效:Nuxt 3 的 SSR 渲染阶段根本无法执行 WebSocket(服务端 Node 环境不支持原生 WebSocket 构造函数),而客户端直连后端又常被 Nginx、Cloudflare 或多实例负载均衡拦截。
- 永远通过相对路径发起连接,例如
new WebSocket('/ws') - 确保 Nginx(或 CDN)配置了 WebSocket 升级头:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" - 如果用
@nuxtjs/proxy,必须开启ws: true,且 target 必须是ws://或wss://协议(不能是http://)
不要在 onMounted 里裸写 new WebSocket()
看似简单,但容易触发重复连接、内存泄漏、SSR hydration 冲突。Nuxt 3 的组件生命周期中,onMounted 在客户端执行,但若用户刷新页面或服务端预渲染完成前就执行了 socket.onopen,状态就不同步了。
- 用
onBeforeUnmount显式关闭 socket,避免标签页切换后还在发消息 - 把 socket 实例存在
ref或useState里,避免每次重渲染都新建 - 加一层连接状态管理,比如
const status = ref,避免重复调用socket.send()导致报错InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state - 别在
setup()顶层直接 new,那会在服务端也执行(报错)
Nuxt 3 服务端无法创建 WebSocket 客户端,但能处理升级请求
你不能在 server/api/xxx.ts 里写 new WebSocket('wss://...')——Nitro 运行时默认不带 WebSocket 客户端能力。但你可以用 defineEventHandler 拦截 Upgrade: websocket 请求,自己实现服务端 WebSocket 接入点(比如对接 Redis pub/sub 或转发给独立 ws 服务)。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 服务端要响应 WebSocket 握手,必须检查
event.node.req.headers.upgrade === 'websocket' - 推荐用
h3提供的sendProxy+ 独立 ws 服务(如ws库起的WebSocketServer),而不是在 Nitro 里硬扛连接 - 若需认证,可在握手阶段读取 cookie 或 token:用
parseCookies(event)获取 session,再决定是否event.node.res.end()拒绝 -
server/routes/ws.ts是更清晰的入口,比塞在api/下更符合语义
多实例部署时,WebSocket 连接必须绑定到同一台机器
如果你用 PM2 cluster 或 Kubernetes 多副本,又没做 sticky session,用户第一次连 A 节点,第二次请求路由到 B 节点,那发来的消息就丢了——因为 WebSocket 连接只存在于 A 节点内存里。
- Nginx 必须配置
ip_hash或基于 cookie 的 session 持久化 - 更可靠的做法是引入 Redis:所有节点都订阅同一个 channel,用
PUB/SUB广播消息,WebSocket 连接只负责收发本机事件 - 不要依赖
process.env.NODE_ENV === 'development'来切 ws 地址,环境变量在构建时就固化了,生产环境改配置得重新部署
真正难的从来不是“怎么写那一行 new WebSocket”,而是连接如何穿透代理、状态如何跨组件同步、断线后怎样不丢数据、多节点间怎么保持一致——这些细节不处理,上线第一天就会收到大量“消息收不到”的反馈。










