Workerman不能直接与CDN建立长连接,因CDN默认不透传WebSocket Upgrade请求且强制超时;正确做法是CDN仅加速静态资源和短连接API,WebSocket必须直连Workerman后端,通过Nginx反向代理并配置Upgrade头透传。

Workerman 本身不能直接与 CDN 建立或维持长连接——CDN(尤其是 HTTP/HTTPS 类)天然不透传 WebSocket 或裸 TCP 连接,也不转发 Upgrade 请求。所谓“Workerman 结合 CDN 实现长连接”,本质是分层解耦:CDN 负责静态资源加速与部分 HTTP 短连接卸载,而长连接通道(如 WebSocket)必须绕过 CDN,直连 Workerman 后端服务。
为什么 CDN 通常不支持 WebSocket 长连接?
主流 CDN(Cloudflare、阿里云 CDN、腾讯云 CDN)对 WebSocket 的支持有严格限制:
- 仅部分企业版/付费版开启 WebSocket 支持,且默认关闭;免费版基本不透传
Upgrade: websocket请求头 - 即使开启,CDN 会强制设置自身心跳超时(如 Cloudflare 默认 100 秒),且不保证
Ping/Pong帧透传,容易触发假断连 - CDN 无法识别或路由
onMessage中的业务心跳(如自定义"ping"字符串),只认标准 WebSocket ping 帧 - 所有 WebSocket 连接在 CDN 节点处终止,后端看到的是 CDN 节点 IP,丢失真实客户端 IP,
$connection->remoteIp失效
Workerman 直连 + CDN 静态分流的典型架构
真正可行的“结合”方式是职责分离:
- CDN 只代理静态资源(
/static/、/js/、/favicon.ico)和部分 HTTP API(如登录、获取房间信息等无状态短连接请求) - WebSocket 连接地址(如
wss://api.example.com:2828)必须配置为 直连 Workerman 服务器 IP 或 SLB(非 CDN),DNS 解析跳过 CDN CNAME - 若需 HTTPS 加密,用 Nginx 做 TLS 终结(监听 443 → 反向代理到 Workerman 的
ws://127.0.0.1:2828),而非让 CDN 终结 WebSocket - Workerman 入口协议必须写成
websocket://0.0.0.0:2828,不能写http://或漏掉协议前缀,否则onMessage不触发
如何避免 CDN 干扰 WebSocket 握手?
常见错误是把 WebSocket 地址也走 CDN 域名,导致 400 或连接立即关闭。关键检查点:
- 前端 JS 中
new WebSocket('wss://cdn.example.com:2828')❌ —— 应改为new WebSocket('wss://ws.example.com:2828'),且ws.example.comDNS 指向 Workerman 服务器或负载均衡器 - Nginx 配置中必须显式允许升级:
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; - Workerman 的
onConnect回调里不要依赖$_SERVER,它为空;真实 IP 需从 Nginx 的X-Real-IP头取(Nginx 要配proxy_set_header X-Real-IP $remote_addr;),然后在onConnect中手动赋值:$connection->real_ip = $_SERVER['HTTP_X_REAL_IP'] ?? $connection->remoteIp; - CDN 缓存规则务必排除所有 WebSocket 路径,例如禁止缓存
/ws*、*.websocket类路径(虽然实际不生效,但避免误配置)
高并发下的连接分流真正在哪做?
CDN 不负责长连接分流,真正的分流靠三层机制:
-
DNS 轮询或 GSLB:将
ws.example.com解析到多个机房的 VIP,实现地理级分流 - 四层负载均衡(LVS / SLB):基于 IP+端口转发 TCP 流量到后端多台 Workerman 服务器,不解析应用层内容,零延迟
- GatewayWorker + Register 服务:当单机 Workerman 连接数逼近 10 万时,用 GatewayWorker 做接入网关,Register 协调各 Gateway 间消息路由,实现水平扩展
这里最容易被忽略的是:Workerman 的 Worker::runAll() 进程一旦启动就不再接受新连接分配逻辑——连接分流必须在 TCP 层完成,不能指望 PHP 代码做“智能路由”。所有“动态扩缩容”“按用户 ID 分片”都得前置到负载均衡或 Gateway 层,Workerman 本身只管稳住单机上的数万连接。

















