微信小程序无法直连workerman的websocket,因微信强制要求tls证书有效、wss协议及完整http upgrade流程,而workerman不处理https握手与upgrade请求,必须通过nginx反向代理实现tls终结与协议升级。

Workerman 本身不能直接对接微信小程序的 wss 连接,必须用 Nginx 反向代理做 TLS 终结 + 协议升级,Workerman 只监听本地 ws:// 地址;否则小程序会卡在 connecting 状态,几秒后报 fail net::ERR_CONNECTION_REFUSED 或 fail WebSocket is not supported。
为什么小程序连不上 Workerman 的 WebSocket?
微信强制校验三点:有效 TLS 证书(不能是自签、不能是 IP)、标准 wss:// 协议名(不接受 _wss 等自定义前缀)、HTTP Upgrade 流程完整。而 Workerman 原生 Worker('websocket://...') 不处理 HTTPS 握手,也无法响应浏览器或小程序发来的 Upgrade: websocket 请求。
常见错误配置包括:
- 直接让 Workerman 监听 443 端口并启用 SSL,但没配 Nginx,或证书链不全
- 小程序前端写的是
wss://yourdomain.com:2346(端口暴露给小程序),但服务器没开该端口或防火墙拦截 - 域名没加到小程序后台的「业务域名」和「request 合法域名」白名单里
- Workerman 启动时用了
0.0.0.0,但 Nginx 反代目标写成了127.0.0.1:2346,而实际监听的是127.0.0.1:2346或localhost:2346,导致连接被拒绝
Nginx 反向代理 wss 必须透传哪些头?
Nginx 不只是转发请求,它必须明确告诉后端(Workerman)这是一个 WebSocket 升级请求,否则握手失败。关键配置项如下:
-
proxy_http_version 1.1:必须设为 1.1,HTTP/1.0 不支持 Upgrade -
proxy_set_header Upgrade $http_upgrade:把客户端的Upgrade: websocket头原样传下去 -
proxy_set_header Connection "upgrade":固定值,不是变量;引号不能少 -
proxy_pass http://websocket_backend:后端地址必须是http://开头(即使 Workerman 跑的是 ws),不能写成ws://
示例 upstream 配置:
由于微信的大热,为了更好的方便使用微信的用户查询一些信息,这篇文章是入门级的微信公众平台开发教程,需要的朋友可以参考下 这篇入门教程将引导你完成如下任务: 创建百度云平台应用启用微信公众平台开发模式获取订阅、文字、图片、语音、视频消息回复文本、图文及音乐消息程序开发
upstream websocket_backend {
server 127.0.0.1:2346;
}
对应 server 块内 location 需包含上述四行,且 location 路径要和小程序 wx.connectSocket({ url: 'wss://...' }) 中的路径一致(比如都用 /ws)。
Workerman 代码里怎么处理登录与消息路由?
小程序每次连接都是新 TCP 连接,没有 Cookie,靠 URL 参数或首次 onMessage 携带身份信息。典型做法是:
- 小程序发起连接时带上参数:
wss://yourdomain.com/ws?uid=123&token=xxx - 在
$worker->onConnect回调中解析$connection->getRemoteIp()和 URL 查询参数(需自行 parse,Workerman 不自动解析) - 收到首条消息后验证 token、绑定
$connection->uid,再存入全局数组或 Redis;未验证前可限制只允许发登录包 - 客服系统需要区分用户与坐席,建议用
GatewayWorker框架而非裸 Worker,它内置bindUid、joinGroup、sendToUid等方法,避免手动遍历 connections
裸 Worker 示例片段(不推荐用于生产客服系统):
$worker->onMessage = function($connection, $data) {
if (!isset($connection->uid)) {
$msg = json_decode($data, true);
if (isset($msg['type']) && $msg['type'] === 'login' && verify_token($msg['token'])) {
$connection->uid = $msg['uid'];
$connection->send(json_encode(['status' => 'ok']));
return;
}
$connection->close();
return;
}
// 正常消息处理
};
证书和域名最容易被忽略的三个点
很多调试失败其实卡在基础设施层,不是代码问题:
- 证书必须是「由可信 CA 签发」,Let’s Encrypt 免费证书可用,但不能用 OpenSSL 自签、不能用腾讯云/阿里云的「免费 DV 试用版」(部分旧版本不被微信信任)
- 域名必须已备案(国内服务器),且在小程序管理后台「开发管理 → 业务域名」中添加,协议必须带
https://,不能只写域名 - Nginx 的
ssl_certificate和ssl_certificate_key路径必须是绝对路径,且 PHP 进程(即 Workerman)不需要读证书,只有 Nginx 需要
复杂点在于:微信校验是端到端的——它既检查你域名的证书有效性,也检查 Nginx 是否正确完成了 TLS 握手和 Upgrade 转发。任一环节断开,wx.connectSocket 就不会触发 onOpen。










