主进程管理 websocket 连接才是稳定长连接的唯一可行路径;渲染进程直接 new websocket() 会因页面刷新、窗口关闭等导致连接强制关闭,须由主进程用 ws 库持单例连接,通过 ipc 暴露安全接口,并实现指数退避重连与心跳保活机制。

主进程管理 WebSocket 连接才是稳定长连接的唯一可行路径。渲染进程里直接 new WebSocket() 看似简单,但页面刷新、窗口关闭、DevTools 重载都会立刻断开连接,根本谈不上“长连接”。
为什么不能在 renderer.js 里直接 new WebSocket()
这是最常踩的坑:你在 renderer.js 里写 const ws = new WebSocket('wss://...'),连上了、收发也正常——但只要用户按 F5 刷新页面,ws 实例就被 GC,连接强制关闭,且无法恢复。
- Electron 渲染进程本质是 Chromium 标签页,生命周期和网页完全一致
- 即使启用
nodeIntegration: true,也无法绕过这个底层限制 - 调试时打开 DevTools → 切换到 Network → 刷新,你会清楚看到 WebSocket 连接状态变为
Closed - 多窗口场景下,每个窗口都建一个连接,服务器压力陡增,还可能触发限流
主进程用 ws 库 + IPC 暴露安全 API 的标准写法
必须用 Node.js 生态的 ws 库(不是浏览器原生 WebSocket),由主进程持有连接实例,并通过 ipcMain 和 contextBridge 暴露受控接口。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 安装依赖:
npm install ws@8.18.3 --save(避免用高版本 9.x,存在 TLS 兼容问题) - 主进程中创建单例连接:
ws实例保存在模块顶层变量或WebSocketManager类中,确保全局唯一 -
preload.js里用contextBridge.exposeInMainWorld()只暴露connect()、send()、onMessage()等必要方法,不暴露原始ws对象 - 所有消息收发都走
ipcRenderer.send()/ipcMain.on(),主进程负责转发和错误处理
自动重连必须自己实现,Electron 不提供内置机制
ws 库本身没有重连逻辑,断开后不会自动尝试重建。你得手动控制重试节奏和退出条件,否则会陷入无限重连风暴。
- 用
lockReConnect布尔锁防止并发重连请求 - 重连间隔建议指数退避:
1s → 2s → 4s → 8s,最大重试次数设为5(可配) - 触发重连的条件不止是
ws.onclose,还要监听ws.onerror和网络就绪事件(如online事件) - 重连前检查
ws?.readyState !== WebSocket.CONNECTING,避免重复调用new ws()
心跳保活和连接状态同步容易被忽略
很多开发者只做了连接建立和消息收发,但没处理“连接看似活着、实则已失效”的情况——比如防火墙静默丢包、NAT 超时、服务端异常下线。
- 必须在主进程定期发送
ws.send('ping'),并监听服务端返回的pong响应 - 连续 3 次未收到
pong,就主动ws.close()并触发重连 - 连接状态(
connecting/open/closed)要通过ipcRenderer.invoke()同步给渲染进程,用于 UI 显示“正在重连中…” - 不要依赖
ws.readyState在渲染进程判断状态——它可能早已过期,主进程才是唯一可信源










