WebSocket握手失败主因是监听地址为127.0.0.1、Nginx未透传Upgrade头、云防火墙未放行端口、Token误放Header中;须改0.0.0.0、配全三行代理头、开通安全组及用URL传参。

监听地址写成 127.0.0.1,外部根本连不上
这是生产环境最典型的低级错误。比如 Workerman 的 $socket = 'websocket://127.0.0.1:2346' 或 Swoole 配置里 'host' => '127.0.0.1',意味着只监听本地回环地址——浏览器从公网或局域网发起连接时,TCP 层就直接拒绝,连握手都触发不了。
- 务必改成
0.0.0.0(监听所有网卡),例如:websocket://0.0.0.0:9999或'host' => '0.0.0.0' - 改完后必须重启服务(
php start.php restart或php think swoole:restart),否则配置不生效 - 用
netstat -tuln | grep :9999确认监听的是*:9999而非127.0.0.1:9999
Nginx 反向代理没配对,握手被静默截断
用了 Nginx 做 wss 代理却只写了普通 HTTP 配置?那 WebSocket 握手请求(含 Upgrade: websocket 和 Connection: upgrade)根本传不到后端,Nginx 默认按 HTTP/1.0 处理并返回 400 或直接断连。
- location 块中三要素缺一不可:
proxy_http_version 1.1;、proxy_set_header Upgrade $http_upgrade;、proxy_set_header Connection "upgrade"; - 禁用缓存:
proxy_cache off;(WebSocket 不允许缓存 101 响应) - 检查 Nginx 错误日志,出现
upstream sent no valid HTTP/1.0 header就是典型握手失败信号
云服务器安全组 / 防火墙没放行端口
宝塔面板里开了端口 ≠ 服务器系统防火墙放行 ≠ 云厂商安全组放行。三个地方任意一个拦截,wss:// 连接会卡在 TCP SYN 阶段,浏览器报 ERR_CONNECTION_REFUSED;ws:// 则可能报 net::ERR_CONNECTION_TIMED_OUT。
- 阿里云/腾讯云:进入「安全组」→ 添加入方向规则,协议类型选「自定义 TCP」,端口范围填你的 WebSocket 端口(如
9999/9999) - Linux 系统防火墙:
firewall-cmd --permanent --add-port=9999/tcp(CentOS)或ufw allow 9999(Ubuntu) - 宝塔面板:「安全」→ 放行对应端口,并确认「防火墙」开关已开启
Token 或认证参数放在 Header 里,浏览器根本不发
原生 new WebSocket(url) 不支持传自定义 Header。很多开发者把 Token 写成 new WebSocket(url, { headers: { Authorization: 'Bearer xxx' } }),这语法在标准 API 中无效,Header 被完全忽略,导致后端鉴权失败而主动断连。
立即学习“PHP免费学习笔记(深入)”;
- 正确做法:把 Token 放在 URL 查询参数中,例如
ws://your.com/ws?token=abc123 - 服务端在
onOpen回调里通过$request->get['token']或类似方式获取并校验 - 避免使用任何依赖封装库的“高级”构造方式,除非你明确知道它底层做了 proxy 或 iframe hack



















