yii框架本身不内置websocket服务器,需集成workerman、swoole或ratchet等独立进程实现;因http与websocket协议及生命周期根本不同,无法在yii\web\application中直接运行websocket服务。

Yii 框架本身不内置 WebSocket 服务器,所有“Yii 实现 WebSocket”的说法,本质都是借壳运行:用 Workerman、Swoole 或 Ratchet 等独立进程托管 WebSocket 服务,再通过某种方式与 Yii 的业务逻辑(如模型、数据库、事件)打通。直接在 yii\web\Application 生命周期里启动 WebSocket 是行不通的。
为什么不能直接在 Yii HTTP 应用里跑 WebSocket?
HTTP 和 WebSocket 是两种协议,生命周期完全不同:
• yii\web\Application 是短生命周期 —— 请求进来、路由、渲染、响应、销毁;
• WebSocket 连接是长连接,需要常驻进程持续监听、收发、心跳、管理客户端列表;
• Yii 的请求上下文($request、$response、Session)在 WebSocket 回调中不可用,强行复用会引发状态混乱或内存泄漏。
Workerman + Yii 组件调用最实用,但要注意生命周期
这是目前生产环境最稳妥的组合:Workerman 做底层通信,Yii 只负责业务逻辑复用。
- 不要在
onMessage回调里每次 new Application —— 开销大、DB 连接池无法复用、配置加载冗余 - 推荐做法:在
Worker::onWorkerStart阶段初始化一个轻量yii\base\Application实例(仅加载db、models等必要组件),存为静态属性 - 在
onMessage中复用该实例调用ActiveRecord::findOne()或触发自定义事件,但绝不调用$app->run()或任何涉及 HTTP 路由的逻辑 - 注意 Workerman 多进程下,每个 worker 进程都有一份独立的 Yii 实例,数据库连接也是隔离的 —— 这不是 bug,是设计
Ratchet 在 Yii2 中跑不起来?多半卡在路由和 CLI 启动
Ratchet 是纯 PHP 实现的 WebSocket 库,不依赖扩展,但和 Yii2 集成时容易踩三个坑:
-
composer require cboden/ratchet后,必须用 CLI 启动服务(如php chat-server.php),不能走 Yii 的index.php入口 —— 否则 PSR-7/HTTP 中间件会干扰握手 - 路由配置里的
'chat' => 'chat/index'是误导项 —— Ratchet 不走 Yii 路由,它自己监听端口(如0.0.0.0:8080),前端连的是ws://yourdomain:8080,不是/chat -
SplObjectStorage存连接对象没问题,但别在onMessage里做耗时操作(比如查 10 张表)—— Ratchet 是单线程阻塞模型,会卡住整个服务
消息推送不是“Yii 推”,而是“谁改数据谁通知”
真正的实时性不靠框架自动感知,而靠业务层显式触发。常见模式:
- 用户发评论后,在
Comment::afterSave()里调用file_get_contents("http://127.0.0.1:2121/push?to=all&msg=...")(推给kriss/yii2-web-msg-sender服务) - 订单状态变更时,触发
Event::trigger(Order::class, Order::EVENT_STATUS_CHANGED),监听器里发 HTTP 请求到 Swoole WebSocket 服务的 API 端点 - 避免用 Redis Pub/Sub 直接喂前端 —— Yii 不是消息中间件,
redis->publish()后还得有人订阅并转发,这层桥接必须写清楚
最容易被忽略的一点:WebSocket 服务端和 Yii 应用之间**没有共享内存或自动事件同步机制**。你得自己决定“谁负责发通知”“通知格式怎么定”“失败了要不要重试”。这部分逻辑不会因为用了 yii2-websocket 扩展就自动出现。











