Workerman无Router类,需手动解析数据实现命令路由;应定义清晰协议、处理粘包、避免在onMessage写业务逻辑,禁用WebServer模拟HTTP路由。

Workerman 里没有 Router 类,别硬套 Laravel 那套思路
Workerman 是纯事件驱动的长连接框架,不走 HTTP 请求-响应生命周期,所以不会有现成的路由注册机制。想“加路由”,本质是自己解析客户端发来的数据,再分发到对应处理逻辑——不是配置,而是编码判断。
常见错误现象:Undefined class Router 或死守 $worker->onMessage 里写一堆 if/else 判断 $data['action'],结果协议一变就全乱。
- 必须先定义清晰的协议格式(比如 JSON 包含
cmd和body字段),否则“路由”无从谈起 - 不要在
onMessage回调里直接写业务逻辑,把它当成分发器,只做解析 + 调用 - 如果用的是自定义二进制协议,得先统一处理粘包/半包,否则
cmd字段可能读不全
用 onMessage 实现最简命令路由:解析 + 分发
这是最轻量也最可控的方式。核心就是把不同命令映射到不同函数,避免嵌套过深。
使用场景:IM 消息类型区分(login、chat、heartbeat)、IoT 设备指令(set_temp、get_status)。
示例结构:
// 在 Worker 初始化后注册
$worker->onMessage = function ($connection, $data) {
// 确保是合法 JSON,且含 cmd 字段
$packet = json_decode($data, true);
if (!$packet || !isset($packet['cmd'])) {
$connection->send(json_encode(['error' => 'invalid packet']));
return;
}
// 路由分发表,key 是 cmd,value 是 callable
$routes = [
'login' => [\App\Handler\LoginHandler::class, 'handle'],
'chat' => [\App\Handler\ChatHandler::class, 'handle'],
'heartbeat' => [\App\Handler\PingHandler::class, 'handle'],
];
$handler = $routes[$packet['cmd']] ?? null;
if ($handler && is_callable($handler)) {
try {
call_user_func($handler, $connection, $packet['body'] ?? []);
} catch (\Exception $e) {
$connection->send(json_encode(['error' => 'handler failed']));
}
} else {
$connection->send(json_encode(['error' => 'unknown cmd: ' . $packet['cmd']]));
}
};
- 别把路由表写死在回调里,抽成静态数组或容器注入,方便测试和替换
- 注意
$packet['body']类型安全,前端可能传字符串、对象或空值,?? []是底线防护 - 错误响应要简洁,别暴露堆栈或内部类名,防止被探测
自定义协议下怎么保证 cmd 字段可读?粘包是最大坑
HTTP 协议自带分隔,但 TCP 流没有边界。如果客户端连续发两个包,Workerman 可能一次收到拼在一起的二进制流,导致 json_decode 失败或错位解析。
性能影响:不处理粘包,路由会随机失败;用 substr 或正则暴力截取,CPU 开销大且不可靠。
- 推荐方案:改用
Worker::$protocol = \App\Protocol\CustomProtocol::class;,实现input()方法按协议头分离完整包 - 协议头建议固定长度(如前 4 字节为 body length),这样
input()能准确返回一个完整包字节数 - 千万别在
onMessage里用strpos($data, '}')找 JSON 结束符——多层嵌套、带}的字符串会直接崩
为什么别碰 Workerman 的 WebServer 模块来“模拟路由”
有人试图启动 WebServer worker,然后用 $_GET['route'] 做跳转,这等于把长连接当短连接用,完全违背 Workerman 设计初衷。
兼容性问题:HTTP 模式下连接秒断,无法维持心跳、推送、房间广播等核心能力;同时失去对 WebSocket、TextProtocol 等原生支持。
- 如果你真需要 HTTP 路由,用 Swoole + Hyperf 或 Laravel Octane,别硬塞进 Workerman
- Workerman 的优势在连接复用和高并发长连接,拿它跑 REST API 是买菜刀削苹果——能动,但钝、慢、还伤刀
- 混合架构可以,但必须明确边界:HTTP 接入层(Nginx)→ 转发给 Workerman 的 Gateway(仅做鉴权/分发)→ 再连真正的 Business Worker
真正难的从来不是写个 switch,而是协议设计时就想清楚字段语义、错误码范围、版本兼容策略。这些定不下来,后面加再多层抽象都只是补丁。











