101是websocket握手成功的唯一正确信号,表示http已切换为websocket协议;后续断连源于服务端未接管帧、nginx漏传upgrade头、响应体混入bom/echo、tls证书问题或sec-websocket-accept计算错误。

101不是错误,是WebSocket握手成功的唯一正确信号。看到它说明HTTP已成功切换为WebSocket协议,后续断连一定发生在握手之后的环节——比如服务端没真正接管帧、Nginx漏转发Upgrade头、或响应体里混入了BOM/echo输出。
为什么返回101后socket.readyState还是0
这表示客户端发出了Upgrade请求,服务器也返回了101响应,但浏览器没把连接状态推进到OPEN(1),常见原因有:
-
Sec-WebSocket-Accept值计算错误:必须用客户端传来的Sec-WebSocket-Key拼接固定字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",再做SHA1 + Base64编码 - PHP脚本里有意外输出:比如
echo、var_dump、文件开头BOM、错误日志开启导致header前有空行 - 用了
wss://但服务端没配TLS证书,或证书不被信任,浏览器会静默拦截,Network面板可能根本看不到101响应 - 服务端返回的响应头缺失
Upgrade: websocket或Connection: Upgrade,哪怕只少一个,浏览器也不认
PHP服务端返回101但立刻断连的典型原因
PHP本身不处理WebSocket帧,它只是完成HTTP阶段的响应。断连往往是因为“握手完就退出”,没进入长连接循环:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 用Ratchet时,必须运行在
php bin/console ratchet:server这类守护进程里,不能走php-fpm——否则onOpen()回调执行完进程就结束 - 用Swoole时,
$server->start()必须被调用,且on('open')和on('message')必须注册;漏掉任一回调,客户端发消息无响应,几秒后超时断开 - 用Workerman时,
Worker::runAll()不能漏,且$worker->onMessage必须定义,否则连接建立后无法收发数据
Nginx反向代理下101失败的硬性配置项
只要用Nginx做前端,以下三行必须同时存在,缺一不可,且大小写和引号都不能错:
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_http_version 1.1;
其中$http_upgrade是Nginx内置变量,会自动提取客户端请求里的Upgrade头;如果写成$sent_http_upgrade或漏掉引号,后端就收不到Sec-WebSocket-Key,无法生成Sec-WebSocket-Accept。
最常被忽略的是:101只管握手,不管通信。它像电话拨通的“嘟”声,后面能不能说话,取决于服务端有没有持续监听、有没有正确解析二进制帧、有没有被中间件悄悄截断响应体。










