socket.io 在 yii2 中需独立部署 node 服务,yii2-node-socket 仅作 http 胶水层;php 通过 nodesocket::emit() 调用 node api 推送消息,多实例必须用 redis 适配器实现跨进程广播,前端连接问题优先排查 node 日志、cors、协议一致性及网络通路。

Socket.IO 在 Yii2 里不能直接用 socket.io-client 就完事
因为 Yii2 是 PHP 后端框架,而 Socket.IO 是基于 Node.js 的实时通信方案,yii2-node-socket 这个扩展只是个“胶水层”,它不托管 Socket.IO 服务,也不自动启动 Node 进程。你得自己搭好 Node 服务,再让 Yii2 通过 HTTP 或 Redis 跟它通信。
常见错误现象:Connection refused、GET /socket.io/?EIO=4&transport=polling 404、前端连不上但没报错——基本都是 Node 服务压根没跑,或者 Yii2 配置的 host/port 跟实际 Node 监听的不一致。
- 确认 Node 服务已独立运行(比如用
node server.js启动),且监听在 Yii2 能访问到的地址(别只绑127.0.0.1:3000却让 Yii2 容器去连) -
yii2-node-socket的配置项'host'和'port'必须跟 Node 服务的server.listen()一致,不是 Yii2 自己的域名 - 如果用 Docker,注意网络模式:Yii2 容器要能 ping 通 Node 容器,推荐用
docker-compose同 network 并用 service 名当 host
怎么让 Yii2 主动向 Socket.IO 推送消息(不是等前端发)
这个扩展的核心能力是让 PHP 主动调用 Node 端的接口触发广播,而不是双向长连接。所以你不会在 Yii2 里写 socket.emit(),而是用 NodeSocket::emit() 发起一个 HTTP 请求到 Node 服务暴露的 API。
使用场景:用户下单成功后,向指定房间推送通知;后台管理员踢人时广播下线事件。
-
NodeSocket::emit()底层是 cURL,参数必须严格匹配 Node 服务约定的 body 结构(比如要求带event、data、room字段) - Node 端需自行实现接收 HTTP 请求的路由(如
app.post('/api/emit')),再调用io.to(room).emit(event, data) - 别指望
yii2-node-socket自动处理重连或离线队列——PHP 是无状态的,发失败就真失败了,得自己加重试或落库补偿
Redis 适配器不是可选项,是跨进程广播的刚需
如果你有多个 Yii2 实例(比如负载均衡下的多台 PHP 服务器),或者 Node 进程不止一个,不用 Redis 就没法保证消息发给所有在线客户端。
性能影响:每次 emit() 都会先往 Redis 写一条消息,Node 端订阅该 channel 后再转发。延迟增加 1–5ms,但换来的是可伸缩性。
- Node 服务必须启用 Redis 适配器:
const redis = require('socket.io-redis'); io.adapter(redis({ host: 'redis-host', port: 6379 })); - Yii2 配置里要填对 Redis 地址,和 Node 用的同一套实例,否则两边“各说各话”
- 别用
localhost当 Redis host——Docker 或远程部署时这会直接断掉
前端连不上?先查 Node 服务日志,别翻 Yii2 日志
yii2-node-socket 只负责“喊一嗓子”,连不上 Socket.IO 是 Node 层的问题。90% 的前端连接失败,和 Yii2 配置无关。
容易踩的坑:
- Node 服务没开 CORS,浏览器控制台报
Blocked by CORS policy——得显式设置origins: '*'或具体域名 - 用了 HTTPS 的 Yii2 域名,但 Node 服务只跑 HTTP,Chrome 会拒绝混合内容,必须给 Node 加 HTTPS 或统一协议
- 前端
io('https://api.example.com:3000')写错了端口,实际 Node 听的是3001,这种低级错误极难排查
复杂点在于:整个链路涉及 PHP → HTTP → Node → WebSocket → Redis → 浏览器,任何一环的网络、证书、防火墙、DNS 都可能卡住,得一段段 ping、curl、telnet 验证通路。











