Workerman主动推送后客户端无反应,根本原因是消息虽发出但未真正抵达有效连接:需用$connection->isConnected()校验连接有效性,避免向已断开的残留Connection对象发送;同时确保前端正确解析JSON格式数据,并完整执行UID绑定/解绑及在线状态校验。

Workerman主动推送信息后客户端没反应,说明消息确实发到了连接对象,但前端没收到或没正确处理。这不是网络中断或连接断开的问题,而是推送路径中某个环节被 silently 吞掉或跳过。
确认消息是否真正抵达客户端连接
在推送逻辑里加一行日志,直接在 send() 前打印连接状态:var_dump($connection->isConnected());。如果返回 false,说明这个 $connection 对象早已失效,但你还拿着它发消息——Workerman 不会报错,send() 会静默失败。
这一步必须做。很多开发者以为 foreach($worker->connections as $connection) 就等于“所有在线用户”,其实不是:$worker->connections 里存的是所有曾经连过、尚未被 GC 清理的 Connection 对象,包括已断开但未触发 onClose 的残留项。
用 【$connection->isConnected() === true】 作为 send() 的前置守门员,否则推送就是往黑洞里扔数据。
检查客户端 WebSocket 连接状态是否存活
方法一:前端监听 onclose 事件并打点日志
在建立连接时写:ws.onclose = () => console.log('WebSocket closed:', event.code, event.reason);。如果看到日志但没重连逻辑,那推送必然收不到。
方法二:服务端主动探测心跳响应
给每个连接设置 lastMessageTime 属性,在定时器里遍历检查:if (time() - $connection->lastMessageTime > 45) { $connection->close(); }。不清理假连接,$worker->connections 就会越积越多,后续推送命中无效连接的概率就越高。
验证消息内容格式是否符合前端解析预期
第一步:用 Chrome DevTools → Network → WS → Messages 查看真实收到的数据帧。
第二步:确认你 send() 的是字符串还是数组/对象。
第三步:如果前端用 JSON.parse(event.data) 解析,而你 send('hello') 发的是纯字符串,就会抛 SyntaxError 并静默终止后续逻辑。
这一步最容易被忽略。Workerman 的 send() 不校验内容类型,它只管把字节流塞进 socket。前端代码却严格依赖数据结构。发 JSON 就必须 $connection->send(json_encode(['type'=>'notice','content'=>'xxx']));,不能漏掉 json_encode。
排查 GatewayWorker 中 UID 绑定与解绑是否完整
① 用户登录时调用 Gateway::bindUid($client_id, $uid);
② 用户登出或关闭页面时,必须触发 Gateway::unbindUid($client_id, $uid);
③ 在 onClose 回调里补上 Gateway::deleteClient($client_id);
④ 每次推送前用 Gateway::isUidOnline($uid) 做二次校验。
少做第②步或第③步,会导致 UID 映射残留。你以为推给了 uid=123,实际上 GatewayWorker 内部查到的是一个早已 close 的 client_id,消息根本不会下发到任何 socket。
注意:【Gateway::unbindUid() 必须在 onClose 之前执行】,否则绑定关系还在,但连接已销毁,推送将无目标可投。











