wx.connectSocket调用成功不等于连接可用,真机90%“连不上”问题源于域名、证书或时机:必须配置wss域名+有效证书并加入后台白名单,禁用IP/localhost,iOS需正规CA证书,应封装全局单例、监听前后台、加退避重连、自实现心跳与粘包处理,并每次发消息前校验socketTask有效性。

wx.connectSocket 调用成功不等于连接可用,真机上 90% 的“连不上”问题都出在域名、证书或时机上,不是代码写错了。
必须配对 wss 域名 + 有效证书,否则真机静默失败
小程序强制要求 WebSocket 使用 wss:// 协议,且域名必须提前加到「小程序管理后台 → 开发 → 开发设置 → 服务器域名」里。只填 example.com 或 https://example.com 都不行,必须带协议前缀:wss://example.com。
- 本地开发时开发者工具可勾选“不校验合法域名”,但真机调试或上线后,只要没加白名单,
wx.connectSocket就会静默失败,控制台可能只报fail没具体错误 - 不能用 IP 地址、
localhost或内网地址(真机根本不可达) - iOS 真机对证书极其敏感:自签名证书大概率握手失败;建议用 Let’s Encrypt 或云厂商签发的证书
- 若用云托管(如微信云开发容器),需确认服务已开启 WebSocket 支持,并暴露正确路径(如
/ws)
别在页面 onLoad 里直接 connect,要封装成全局单例
小程序生命周期决定:切后台、前后台切换、内存不足时,系统可能主动 kill 掉 socket 连接,且不会通知你。只在页面级初始化,会导致多个页面重复建连、状态混乱、重连冲突。
- 把连接逻辑挂到
getApp().socket或单独模块里,确保整个小程序只有一条连接 - 必须监听
onHide和onShow:切后台时缓存连接状态,切回前台时检查socketTask.readyState,非OPEN就主动重连 - 重连前先调用
wx.closeSocket(),否则新连接可能被旧socketTask阻塞 - 重连要加退避策略(如 1s、2s、4s…),避免高频失败打爆服务端
消息收发必须自己处理粘包和心跳,小程序不内置
wx.onSocketMessage 每次回调只传一个 res.data,但它不保证和后端一次 send 对应——TCP 层可能拆包或合并。更关键的是,小程序没有内置心跳机制,WSS 连接空闲几分钟就会被中间代理(如 Nginx、微信网关)静默断开。
- 服务端必须定期发心跳帧(如
{"type":"ping"}),小程序收到后立刻回{"type":"pong"} - 前端要自己起定时器,每 30–45 秒发一次
wx.sendSocketMessage({ data: '{"type":"ping"}' }) - 收到消息先
JSON.parse,捕获异常并丢弃非法数据,防止一次脏包导致整个消息流中断 - 如果后端返回的是二进制帧(如
ArrayBuffer),res.data类型是ArrayBuffer,需用new TextDecoder().decode(res.data)转字符串
最常被忽略的一点:连接建立后,socketTask 实例本身不持久——它可能被系统回收,而你保存的引用却还指向一个已失效的对象。所以每次发消息前,务必检查 socketTask && socketTask.readyState === 'OPEN',而不是只依赖一个布尔标志位。



















