真机WebSocket连接失败主因是wss协议、后台域名、SSL证书三者未严格匹配:必须用wss://、域名精确配置到小程序后台socket合法域名栏、证书链完整且TLS1.2+启用。

真机上 WebSocket 连接失败,99% 是因为没配对 wss:// 协议 + 后台域名 + 证书三者中的至少一项。
wss:// 不是可选项,是强制要求
开发工具里用 ws:// 能连通,不代表真机能行——微信真机环境只认 wss://。哪怕你本地 Nginx 反向代理到 http://localhost:3000,客户端 URL 也必须写成 wss://yourdomain.com/ws。
- 写成
ws://或http://:真机直接报Invalid HTTP status,握手阶段就断了 - 写成
wss://但端口非 443(比如wss://yourdomain.com:8080):部分安卓机型会静默失败,不报错也不触发onSocketError - 域名带路径时,
/ws之后的路径由服务器处理,但协议和域名必须完整匹配后台配置
小程序后台“socket 合法域名”必须精确填写
不是填根域名就行。你代码里用的是 wss://api.example.com/ws,后台就必须填 api.example.com,不能只填 example.com,也不能多加 https:// 或路径。
- 配置位置:小程序管理后台 → 开发 → 开发管理 → 服务器域名 →
socket 合法域名栏 - 必须已备案、已解析、且 CNAME 或 A 记录生效(DNS 缓存可能延迟,可用
dig api.example.com验证) - 若用二级域名(如
ws.example.com),需单独添加,不能靠泛域名自动覆盖 - 修改后需重新提交审核或发布新版本才生效;仅开发者工具里勾选“不校验合法域名”对预览/体验版无效
证书和 TLS 版本是隐形拦路虎
即使协议和域名都对,证书链不全或 TLS 版本过低也会导致握手失败,错误仍显示为 Invalid HTTP status,但实际日志里看不到细节。
- 自签名证书:开发工具可过,真机必拒(除非开启调试模式,但预览时无效)
- Let's Encrypt 证书:推荐用
fullchain.pem(含中间证书),只传cert.pem容易在 iOS 上握手失败 - TLS 版本:Nginx 必须显式启用 TLS 1.2+,禁用 TLS 1.0/1.1;配置示例:
ssl_protocols TLSv1.2 TLSv1.3; - 验证方式:用
openssl s_client -connect api.example.com:443 -servername api.example.com看是否返回Verify return code: 0 (ok)
uni-app 中 connectSocket 的调用陷阱
在 uni-app(尤其 Vue3 组合式 API)里,uni.connectSocket 返回的是一个 SocketTask 实例,不是全局监听——这点和原生小程序一致,但容易被忽略。
- 必须用返回值绑定事件:
const task = uni.connectSocket({ url: 'wss://...' }); task.onOpen(...),而非只写uni.onSocketOpen(...) - iOS 下若不传
complete回调,onOpen可能不触发;建议始终带上:complete: () => console.log('init done') - 连接未建立前调用
uni.sendSocketMessage会静默丢弃,务必等onOpen触发后再发认证消息 - 不要在
onSocketClose里立即重连,需加防抖(如 1s 后再试),否则可能陷入连接风暴
最常被绕过的点:你以为配好了域名,其实 DNS 没刷完;你以为证书没问题,其实中间证书漏了;你以为写了 wss:// 就够了,结果 Nginx 没开 WebSocket 支持(proxy_set_header Upgrade $http_upgrade; 忘了加)。每一步都得单独验证,不能靠“看起来对”来判断。



















