PHP Ratchet Push无法接收通知问题排查求助
排查Ratchet WebSocket推送前端收不到消息的问题
我来帮你梳理下几个最可能导致这个问题的方向,你可以逐一排查:
1. 前端WebSocket连接与消息监听是否正常
- 先检查
page.html里的WebSocket连接地址是否正确,比如Ratchet服务端监听的是8080端口的话,连接应该是new WebSocket('ws://localhost:8080'),别写错端口或域名。 - 打开浏览器控制台(F12),切换到Network标签,筛选
WS类型,看WebSocket请求的状态是不是101 Switching Protocols。如果连接失败,控制台会直接抛出错误(比如连接超时、拒绝),这时候要确认服务端确实在运行并监听对应端口。 - 务必确保前端正确监听了
onmessage事件,比如:
很多时候收不到消息只是因为没写const conn = new WebSocket('ws://localhost:8080'); // 监听连接成功 conn.onopen = () => console.log('WebSocket连接成功'); // 监听消息 conn.onmessage = (e) => { console.log('收到推送:', e.data); // 这里要写你自己的消息展示逻辑 }; // 监听错误 conn.onerror = (err) => console.error('WebSocket错误:', err);onmessage或者写错了方法名。
2. 服务端Pusher类的客户端连接管理是否正确
- 检查
bin/push-server.php里是否正确把Pusher实例绑定到Ratchet服务,比如:use Ratchet\Server\IoServer; use Ratchet\Http\HttpServer; use Ratchet\WebSocket\WsServer; use YourNamespace\Pusher; require dirname(__DIR__) . '/vendor/autoload.php'; $pusher = new Pusher(); $server = IoServer::factory( new HttpServer( new WsServer($pusher) ), 8080 // 确保这个端口和前端连接的一致 ); echo "WebSocket服务启动,监听端口8080\n"; $server->run(); - 再看
src/Pusher.php是否正确实现MessageComponentInterface,并且在onOpen时把客户端连接存入存储对象:
如果没有在use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; class Pusher implements MessageComponentInterface { protected $clients; public function __construct() { $this->clients = new \SplObjectStorage(); } public function onOpen(ConnectionInterface $conn) { // 把新连接加入客户端列表 $this->clients->attach($conn); echo "新客户端连接:{$conn->resourceId}\n"; } // 确保实现了onMessage、onClose、onError方法 public function onMessage(ConnectionInterface $from, $msg) {} public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); } public function onError(ConnectionInterface $conn, \Exception $e) {} // 推送方法,遍历客户端发送消息 public function pushMessage($message) { foreach ($this->clients as $client) { $client->send($message); } } }onOpen时保存连接,推送时就找不到要发送的客户端。
3. post.php的推送触发逻辑是否正确
- 重点注意:Ratchet服务是独立运行的进程,
post.php作为Web请求脚本,不能直接实例化Pusher调用推送方法(因为这是两个完全独立的进程,Web进程里的Pusher没有客户端连接)。 - 官方文档推荐用Redis做中间件来触发推送:服务端监听Redis频道,
post.php往该频道发送消息,服务端收到后再推送给客户端。你要确认:- 服务端是否正确绑定了Redis订阅,比如在
bin/push-server.php里添加:$loop = React\EventLoop\Factory::create(); $redis = new React\Redis\Client($loop, ['host' => '127.0.0.1', 'port' => 6379]); $redis->subscribe('push_notifications', function ($message) use ($pusher) { $pusher->pushMessage($message); }); $server = IoServer::factory(new HttpServer(new WsServer($pusher)), 8080, '0.0.0.0'); $server->run(); post.php是否正确往Redis频道发送消息:$redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->publish('push_notifications', '你要推送的内容');
- 服务端是否正确绑定了Redis订阅,比如在
4. Windows环境的特殊限制
- 检查Windows防火墙是否阻止了WebSocket端口(比如8080),可以临时关闭防火墙测试,或者在防火墙里添加允许该端口的入站规则。
- 确认PHP的
sockets扩展是否启用:打开命令行输入php -m,看输出里有没有sockets,如果没有,打开php.ini去掉extension=sockets前面的注释,重启服务。 - 如果用了Redis,确保Redis服务在Windows上正常运行(可以用
redis-cli ping测试,返回PONG就是正常)。
5. 跨域问题(如果前端是HTTP访问)
- 如果你的
page.html是通过http://localhost(80端口)打开,而WebSocket是ws://localhost:8080,端口不同属于跨域场景。虽然WebSocket默认允许跨域,但有些浏览器可能有严格限制,你可以在服务端添加跨域允许:$httpServer = new HttpServer(new WsServer($pusher)); // 允许所有来源,也可以指定你的前端域名 $httpServer->setOriginCheck(function ($origin) { return true; });
如果排查完这些还是没解决,可以把关键代码片段(比如Pusher类的推送方法、post.php的触发逻辑、前端连接代码)贴出来,这样能更精准定位问题。
内容的提问来源于stack exchange,提问作者Hideki Kan
相关产品推荐
相关产品推荐

