uni-app 非h5端不支持 socket.io-client,应统一使用 uni.connectsocket;服务端需配置仅启用 websocket 传输并禁用轮询,客户端手动序列化消息、定时心跳保活,并实现带退避策略的重连逻辑。

uni-app 里不能直接用 socket.io-client
因为 socket.io-client 依赖 Node.js 环境的 net、http 等模块,而 uni-app 的非 H5 端(如微信小程序、App)运行在受限 JS 沙箱或 WebView 中,不支持这些底层 API。直接 yarn add socket.io-client 后调用 io() 会报错:Cannot find module 'net' 或 io is not defined。
实操建议:
- H5 端可正常使用
socket.io-client(需服务端开启 CORS 和 WebSocket 升级支持) - 小程序/App 端必须降级为原生 WebSocket 协议通信 —— 即服务端要同时支持
ws://(或wss://)裸连接,不能只暴露socket.io的长轮询或封装路径 - 推荐服务端用
socket.io并配置transports: ['websocket'],强制禁用轮询,让客户端能“假装”是 WebSocket 连接
uni-app 跨端统一用 uni.connectSocket 就行
这是 uni-app 官方封装的跨平台 WebSocket API,H5、微信小程序、App、支付宝小程序等全部支持,行为一致,不用条件编译切逻辑。
常见错误现象:
- 连上就断:没在
onOpen里发心跳,被服务端或中间代理(如 Nginx)超时踢出 - 收不到消息:服务端发的是
socket.io的协议包(带 event name、ack id 等),但uni.onMessage收到的是原始字符串/ArrayBuffer,没做解析 - 重连失败:没监听
onError或onClose,也没做指数退避重试
实操建议:
- 连接地址写成
ws://your-domain.com,别带/socket.io/?EIO=4&transport=websocket这类 socket.io 自动拼的 query —— 那是给io()用的,uni.connectSocket不认 - 服务端必须用
socket.io的allowEIO3: true+transports: ['websocket'],否则握手阶段就失败 - 发消息前,手动序列化成 JSON 字符串:
uni.sendSocketMessage({ data: JSON.stringify({ event: 'chat', data: 'hi' }) })
怎么让服务端识别 uni-app 的 WebSocket 连接是 “socket.io 客户端”
socket.io 协议不是裸 WebSocket,它有一套握手和帧格式(如 0{"sid":"abc","upgrades":[],"pingInterval":25000,"pingTimeout":5000})。uni-app 的 uni.connectSocket 不会自动发这些,所以服务端默认不会把它当 socket.io 连接处理,socket.emit() 会失效。
解决思路只有两个:
- 服务端改用裸 WebSocket 接收(比如用
ws库),自己解析 JSON 消息,再分发事件 —— 这是最干净的做法,也绕开了 socket.io 的兼容包袱 - 服务端保留 socket.io,但加一层适配:监听
connection事件后,手动模拟 socket.io 的 session 初始化,再把连接挂到io.sockets.adapter上(极不推荐,维护成本高)
参数差异注意点:
-
socket.io默认 pingInterval=25s,uni-app 建议自己每 20s 主动sendSocketMessage发个{"type":"ping"}保活 - 微信小程序对
connectSocket的header支持有限,Authorization 等字段需放在 query 里传,如ws://x.com?token=xxx
App 和小程序里 WebSocket 断连后怎么自动重连
uni-app 的 uni.onSocketClose 和 uni.onSocketError 一定会触发,但直接在里面调 uni.connectSocket 很容易陷入无限重连或内存泄漏。
性能与可靠性要点:
- 必须加重试间隔,从 1s 开始,每次 ×1.5,上限 30s,避免打爆服务端或触发小程序频控
- 记录重连次数,超过 5 次后暂停,等用户操作(如点击“重试按钮”)再继续
- H5 端可用
new WebSocket()替代uni.connectSocket,因为它支持onreconnect类似事件;但跨端一致性优先选uniAPI - App 端要注意:Android 8+ 对后台 WebSocket 有休眠限制,前台切后台后可能静默断开,需监听
uni.onHide主动 close,uni.onShow再 reconnect
容易被忽略的是:WebSocket 连接对象本身没有生命周期绑定,uni.connectSocket 成功后返回的只是一个任务 ID,所有回调(onMessage、onClose)都是全局监听。一旦页面卸载而没手动 uni.closeSocket,回调仍会执行,可能引发 this 指向丢失或 setData 报错。










