workerman不负责历史消息异步加载,仅处理websocket连接与实时转发;历史记录须由后端业务层提供分页api,前端触发请求,workerman仅中转查询结果并推送给指定连接。

Workerman 本身不负责历史消息的异步加载,它只管 WebSocket 连接和实时转发;历史记录必须由后端业务层(比如 TP5、Laravel 或纯 PHP 接口)提供分页 API,前端用 JS 触发请求,Workerman 只在需要时把查询结果推给指定连接。
历史记录不能靠 Workerman 自己查数据库
Workerman 是网络通信框架,不是 ORM 或业务逻辑容器。它没有内置数据库访问能力,也不该直接耦合 MySQL 查询逻辑。常见错误是试图在 $worker->onMessage 里写 mysqli_query 或 PDO::query——这会阻塞整个事件循环,尤其在并发高时导致所有连接卡住。
- 正确做法:把历史查询封装成独立 HTTP 接口(如
/api/chat/history?session_id=xxx&page=1),用 Nginx + PHP-FPM 或 Swoole/TP5 承载 - Workerman 进程只做“中转”:收到前端“我要加载历史”的消息后,用
file_get_contents(不推荐)或更稳妥的workerman/http-client异步调用该接口 - 注意:如果用了
workerman/http-client,必须满足环境要求(PHP ≥ 8.1、revolt/event-loop 已装、workerman ≥ 5.0),否则await $client->get()会直接报Fiber not running
前端触发加载时,Workerman 怎么配合推送?
访客点击“加载更多”,前端 JS 发送一条 WebSocket 消息(例如 {"type":"load_history","page":2}),Workerman 收到后不应自己查库,而是:
- 校验
session_id或用户身份(从连接对象或 handshake 参数中提取) - 调用已准备好的历史接口(推荐用
workerman/http-client异步请求,避免阻塞) - 拿到响应后,解析 JSON,按消息方向(
from: "visitor"/from: "service")补入前端已有消息列表 - 不要直接
$connection->send()原始 HTML 片段;统一返回结构化数据,如{"type":"history_chunk","data":[...],"page":2}
分页参数怎么传、怎么存才不翻车?
历史记录依赖 session 维度,但 Workerman 的 $connection 对象默认不持久化。容易踩的坑:
- 别把
session_id存在内存数组里等下次用——Worker 进程重启就丢,且多进程下不同 Worker 看不到彼此的数组 - 正确方式:前端每次请求带上唯一标识,比如握手时 URL 里的
?sid=abc123,在$worker->onConnect中解析并存为$connection->sid - 后端接口查历史时,必须用这个
sid关联数据库表(如chat_history表要有session_id字段),不能依赖 PHP$_SESSION(Workerman 不走 PHP-FPM 生命周期) - 分页建议用游标(cursor)而非 page/limit,避免新消息插入导致翻页错位;若必须用 page,接口需返回
has_more: true控制“加载更多”按钮显隐
真正麻烦的从来不是“怎么发请求”,而是“谁来保证 session_id 全链路一致”“数据库查询不拖垮 event loop”“分页边界在高并发下不漏不重”。这些细节没对齐,前端再漂亮也撑不过 100 个并发访客。











