onopen不执行最常见原因是websocket握手失败,导致连接未进入onopen阶段;需检查url协议、swoole服务器类型、handshake响应及think-swoole配置是否启用websocket模块并正确绑定swoole.websocket.connect事件。

onOpen 为什么完全不执行
最常见原因是 WebSocket 握手失败,导致连接根本没走到 onOpen 阶段。Swoole 的 onOpen 只在握手成功后触发,而握手失败时连日志都不会打——你看到的只是客户端报错 Error during WebSocket handshake,服务端却静默。
- 检查客户端 URL 是否带
ws://或wss://,不是http://;用浏览器 DevTools 的 Network 标签页确认请求 Method 是GET、Header 含Upgrade: websocket - 确认 Swoole 服务器监听的是 HTTP 协议端口(如
9501),不是原始 TCP 端口;WebSocket 必须基于Swoole\Http\Server或Swoole\WebSocket\Server,不能用Swoole\Server - 如果你手动设置了
onHandShake回调,但没调用$response->status(101)+$response->end(),握手会卡住,onOpen永远不会触发
ThinkPHP 6 + think-swoole 中 onOpen 不生效
TP6 的 think-swoole 扩展把原生 Swoole 事件做了封装,onOpen 并不直接暴露给开发者。它对应的是事件名 swoole.websocket.Connect,由框架内部映射到 onOpen 行为。如果你注册了 WsConnect 监听器但没反应,大概率是配置或绑定问题。
-
config/swoole.php中websocket.enable必须为true,且server.type应为websocket(不是http) -
app/event.php的listen数组里,键必须严格写成'swoole.websocket.Connect',少一个点、大小写错误(比如写成Swoole.WebSocket.Connect)都会失效 - 监听器类(如
app\listener\WsConnect)的handle方法接收参数是\Swoole\WebSocket\Server $server, \Swoole\Http\Request $request,不是原生onOpen的两个参数顺序——框架已帮你转好了
FD 能打印出来,但 onOpen 逻辑没跑
能拿到 $request->fd 说明握手已完成,onOpen 实际上已经触发了。所谓“没跑”,往往是日志被缓冲、输出被忽略,或者你在错误位置加了调试代码。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 别在
onOpen里用var_dump()或print_r():Swoole Worker 进程默认关闭了stdout输出,这些会直接丢弃;改用echo "onOpen triggered\n"+file_put_contents('/tmp/debug.log', ... , FILE_APPEND) - 确认你修改的是实际被加载的监听器文件;TP6 的
make:listener命令生成的类在app/listener/下,但如果你手动生成过同名类在别的命名空间,Autoloader 可能加载错了 - 如果用了多 Worker 进程(
worker_num > 1),而你只在控制台看一个进程的日志,其他 Worker 的onOpen输出就看不到——加echo "[pid:" . getmypid() . "] onOpen\n"区分
为什么 onMessage 正常,onOpen 却不触发
这种情况极少见,但一旦发生,基本锁定为「连接复用」或「伪断连」:客户端发完消息才建立连接,或者用的是旧版 Swoole(onOpen 触发时机有偏差。
- 检查客户端是否跳过了握手,直接发
text帧(比如用curl -X GET模拟,这根本不是合法 WebSocket 客户端) - 升级 Swoole 到
5.1+:老版本在高并发下偶发onOpen延迟或丢失,新版本协程 WebSocket 层修复了多数边缘 case - 临时加个
tick定时器,在连接建立后 100ms 再检查$server->exists($fd),如果存在但没进onOpen,说明底层事件分发异常,需换内核或重装 Swoole
真正难排查的从来不是 onOpen 该不该触发,而是你以为它没触发,其实它早触发完了——只是你没在正确的地方、用正确的方式去捕获它。










