swoole websocket跨域连接失败主因是nginx未透传upgrade和connection头或swoole未正确响应握手;需配置proxy_set_header upgrade $http_upgrade、connection "upgrade"、proxy_http_version 1.1,并确保swoole常驻运行。

直接说结论:Swoole WebSocket 跨域连接失败,90% 是 Nginx 反向代理没透传 Upgrade 和 Connection 头,或 Swoole 服务端未正确响应握手请求——不是前端写错 URL,也不是浏览器限制本身。
为什么 Nginx 必须显式配置 proxy_set_header Upgrade $http_upgrade
WebSocket 握手本质是一次 HTTP 协议升级请求,客户端发的原始请求里带 Upgrade: websocket 和 Connection: Upgrade。Nginx 默认只转发基础头,这两个关键头会被静默丢弃。后端 Swoole 收不到,就当普通 HTTP 请求处理,直接返回 404 或 403。
-
proxy_http_version 1.1不可省略:HTTP/1.0 不支持 upgrade 机制 -
$http_upgrade是 Nginx 内置变量,值来自客户端原始请求;写成"websocket"或$upgrade都无效 -
proxy_set_header Connection "upgrade"中的双引号不能少,否则nginx -t会报语法错误 - 改完必须执行
nginx -s reload,只改配置不重载等于白配
Swoole 服务端返回 403 的真实原因
不是 CORS 问题,而是握手阶段被拦截。Swoole 自身不校验 Origin,但如果你用了中间件(如 Laravel Swoole、Hyperf、或自定义路由逻辑),很可能在 onRequest 阶段就做了权限判断,把 WebSocket 握手请求当成普通 HTTP 拦下了。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 检查是否在
onRequest回调里写了return $response->status(403)类逻辑 - 确认
onOpen是否只对Upgrade: websocket请求触发——如果不是,说明握手根本没进到这一步 - 用
curl -i -H "Upgrade: websocket" -H "Connection: Upgrade" http://127.0.0.1:9502/ws直连 Swoole,看是否返回101 Switching Protocols - 如果直连成功但走 Nginx 就 403,100% 是 Nginx 配置漏项或某层网关(如 Cloudflare)没透传头
wss 连接提示“net::ERR_CONNECTION_CLOSED”怎么查
这个错误通常出现在 TLS 层断开,和 WebSocket 协议无关。重点排查证书链和代理超时。
- 用
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com看是否能完成 TLS 握手,关注Verify return code是否为 0 -
proxy_read_timeout必须设大(如3600s),否则空闲连接会被 Nginx 主动关闭,触发浏览器静默断连 - 宝塔面板里开启 SSL 后,默认可能只配了
listen 443 ssl,但没加http2或证书链完整路径,导致部分客户端(尤其是 iOS)握手失败 - 确认 Swoole 启动时监听的是
0.0.0.0:9502而非127.0.0.1:9502,否则 Nginx 从本机 proxy_pass 可能因 bind 失败而 fallback 到错误端口
最易忽略的一点:Swoole WebSocket 服务必须是常驻进程,不能跑在 PHP-FPM 下——FPM 模式下即便返回了 101,连接也会立刻断开,因为 PHP 生命周期结束就 kill 进程了。这点一旦错,所有配置都白搭。










