workerman onmessage收不到数据,首要确认客户端使用ws://协议、在onopen后send、服务端worker协议为websocket://;其次检查前端是否json.stringify发送、避免用postman等工具误测,排查onmessage是否被覆盖或缓冲区污染。

Workerman onMessage收不到数据,意味着客户端已成功建立连接,但服务端始终无法触发onMessage回调,常见于WebSocket或TCP长连接场景。这既不是网络不通,也不是进程未启动,而是数据在抵达onMessage之前就被拦截、丢弃或根本没进入正确处理流程。
客户端发的数据压根没走WebSocket协议
第一步:确认客户端连接的是ws://或wss://,而不是http://——浏览器用new WebSocket('http://xxx')会静默失败,控制台报错“Invalid URL”,但onConnect仍会触发,后续send无响应。
第二步:检查客户端是否在open事件后才调用send()。若在onopen前就send({msg:'hi'}),Workerman不会报错,但该消息会被内核丢弃,onMessage永不触发。
第三步:用Chrome开发者工具→Network→WS→Messages面板,看「Frames」里有没有Outgoing Message。没有发送记录,说明问题出在前端;有发送但右侧没Incoming,说明服务端没收到或没进onMessage。
服务端监听的不是WebSocket协议
检查$worker初始化时的协议类型:【必须是'websocket://'开头,不能写'tcp://'或'http://'】。写成$worker = new Worker('tcp://0.0.0.0:2345'),即使前端连ws://,Workerman也只当裸TCP处理,不会解WebSocket帧,$data永远为null。
方法一:改协议头
把'tcp://0.0.0.0:2345'换成'websocket://0.0.0.0:2345',并确保Workerman版本≥3.5.0(旧版不支持原生WebSocket)。
方法二:手动加载WebSocket协议类(兼容老版本)
require_once __DIR__ . '/Workerman/Protocols/WebSocket.php';
$worker = new Worker('tcp://0.0.0.0:2345');
$worker->protocol = \Workerman\Protocols\WebSocket::class;
客户端发的是原始字符串而非标准WebSocket帧
前端必须用WebSocket.send()发送UTF-8字符串,不能直接send({a:1})——这会触发TypeError且消息被浏览器丢弃。正确做法是:ws.send(JSON.stringify({msg:'hello'}))。
Apifox、Postman或curl测试时,默认发送raw文本,不是WebSocket帧。这类工具根本无法模拟WebSocket握手和帧格式,【强行用它们测onMessage注定失败】。
真正有效的调试方式只有两种:浏览器原生WebSocket + console.log,或用wscat命令行工具:wscat -c ws://localhost:2345,连接成功后手动输入字符串回车发送。
Workerman接收缓冲区被污染或协议解析中断
如果服务曾处理过非法帧(比如客户端强行断开、发送非UTF-8字节、超长payload),Workerman内部WebSocket协议解析器可能卡在中间状态,后续合法帧也被跳过。此时onMessage不再触发,但连接仍显示活跃。
解决办法:重启Worker进程。不要只reload,要stop再start,确保协议解析器状态重置。
预防措施:在onMessage开头加兜底判断:if (!is_string($data) || empty($data)) { return; },避免空值干扰后续逻辑。
onMessage回调被意外覆盖或未绑定
检查是否写了多次$worker->onMessage = function() {...}。PHP中后赋值会完全覆盖前一个,如果你在不同文件或条件分支里重复赋值,最后一处生效,前面的逻辑彻底丢失。
典型错误:在Worker启动前先设了一个通用onMessage,又在某个if分支里重新赋值,结果只有分支成立时才生效;分支不成立时,onMessage为空函数,收不到任何数据。
验证方式:在onConnect里var_dump($worker->onMessage),输出NULL就说明没绑定,输出Closure说明已绑定。











