open_websocket_close_frame 控制是否将 WebSocket 关闭帧(opcode 0x08)投递给 onMessage 回调,默认 false 即忽略;设为 true 后可在 onMessage 中通过 $frame->opcode === 0x08 判断并获取 $frame->code 和 $frame->reason,用于区分关闭类型、记录日志或清理资源,但不会阻止自动断连和 onClose 触发。

open_websocket_close_frame 控制是否接收关闭帧
这个配置项决定 Swoole 是否把 WebSocket 的 close 帧(opcode 0x08)当作普通消息投递给 onMessage 回调。默认是 false,即忽略关闭帧、不触发 onMessage;设为 true 后,关闭帧会进入 onMessage,你才能在代码里读取 $frame->code 和 $frame->reason。
为什么需要手动开启它
大多数业务不需要处理关闭帧细节——Swoole 底层收到 close 帧后会自动断开连接,并触发 onClose 回调,这就够了。但如果你要:
- 区分客户端是主动关闭(带 reason)还是异常断连(无 reason)
- 记录关闭原因用于日志或监控(比如 code 4001 表示用户退出,4999 表示踢出)
- 在关闭前做清理(如释放 Redis 锁、更新在线状态),且必须依赖客户端传来的 reason 字符串
那就得打开 open_websocket_close_frame,否则 $frame->reason 永远为空,$frame->code 也拿不到。
开启后 onMessage 里怎么判断是关闭帧
不能只靠 $frame->data 是否为空,必须检查 $frame->opcode:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
$frame->opcode === 0x08才是关闭帧(其他常见值:0x01 文本,0x02 二进制) -
$frame->code是整数(如 1000 正常关闭,1001 离开,4000+ 是自定义) -
$frame->reason是字符串,可能为空(例如浏览器直接关标签页)
示例判断逻辑:
if ($frame->opcode === 0x08) {
echo "Close frame: code={$frame->code}, reason='{$frame->reason}'\n";
// 这里可做自定义响应或记录
return;
}
// 其他消息正常处理
容易踩的坑
开启后不加 opcode 判断,直接对所有 onMessage 数据做 JSON 解析或广播,会导致错误:
- 关闭帧的
$frame->data是空字符串或二进制 payload,json_decode($frame->data)返回 null,后续逻辑崩掉 - 误把关闭帧广播给其他人,前端收到空内容或解析失败,UI 异常
- 没在处理完关闭帧后
return,继续执行后续业务逻辑(比如存数据库),浪费资源
最关键一点:即使开了 open_websocket_close_frame,Swoole 仍会在处理完 onMessage 后自动断开连接并触发 onClose。你不能靠它“拦截”关闭行为——它只是让你看见关闭帧,不是让你阻止关闭。

















