onRequest是WebSocket服务器暴露HTTP接口的刚需通道,因swoole_websocket_server继承自swoole_http_server,天然支持HTTP请求;未注册onRequest时非WebSocket请求会直接返回400错误。

onRequest 是 WebSocket 服务器对外暴露 HTTP 接口的唯一入口,不是可选补充,而是主动推送、健康检查、管理控制的刚需通道。
为什么 WebSocket 服务器能用 onRequest
Swoole 的 swoole_websocket_server 类继承自 swoole_http_server,所以它天然支持 HTTP 协议层能力。只要没显式禁用或覆盖,收到非 WebSocket 握手的 HTTP 请求(比如 GET /push?uid=1001)就会触发 onRequest 回调,而不是直接返回 400 错误。
常见错误现象:启动了 WebSocket 服务,但用 curl http://localhost:9501/health 得到空白响应或 400 —— 这是因为没定义 onRequest 回调,Swoole 默认拒绝非升级请求。
- 必须手动注册
onRequest,否则所有非 WebSocket 请求都会被丢弃 -
onRequest和onOpen/onMessage运行在同一个进程内,共享内存(如全局数组、Swoole\Table),但不共享协程上下文 - 不能在
onRequest里直接调用$server->push(),因为没有$fd;得先查连接状态,再发消息
onRequest 里怎么安全地向 WebSocket 客户端发消息
核心难点是:HTTP 请求不知道哪个客户端该收这条消息,所以得靠外部标识(如用户 ID、房间号)反查在线连接。推荐用 Swoole\Table 做映射表,比 PHP 数组更安全、支持多进程读写。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
示例逻辑:
<pre class="brush:php;toolbar:false;">$table = new Swoole\Table(1024);
$table->column('uid', Swoole\Table::TYPE_STRING, 64);
$table->column('fd', Swoole\Table::TYPE_INT, 8);
$table->create();
$server->on('open', function ($server, $request) use ($table) {
$uid = $request->get['uid'] ?? '';
if ($uid) {
$table->set($uid, ['uid' => $uid, 'fd' => $request->fd]);
}
});
$server->on('close', function ($server, $fd) use ($table) {
foreach ($table as $key => $row) {
if ($row['fd'] == $fd) {
$table->del($key);
break;
}
}
});
$server->on('request', function ($request, $response) use ($server, $table) {
if ($request->server['request_uri'] === '/push' && $request->get['uid']) {
$uid = $request->get['uid'];
$row = $table->get($uid);
if ($row && $server->exist($row['fd']) && $server->isEstablished($row['fd'])) {
$server->push($row['fd'], $request->get['msg'] ?? 'no message');
$response->end('OK');
} else {
$response->status(404);
$response->end('offline');
}
return;
}
$response->status(404);
$response->end('Not Found');
});
- 别用
$_GET 或全局变量传 <code>uid,必须从$request->get取,这是 Swoole 封装后的干净数据 - 每次
push前必须调用$server->exist()和$server->isEstablished(),避免向已断开但未触发onClose的fd发送数据导致崩溃 -
Swoole\Table不支持复杂结构,不要存对象或闭包;只存基础类型字段
onRequest 和 onMessage 共享资源要注意什么
两者都运行在 Worker 进程里,可以共用 Swoole\Memory\Map、Swoole\Table、Redis 连接池等跨请求资源,但不能共用普通 PHP 变量或静态属性——Worker 进程会复用,不同请求可能污染彼此状态。
- 禁止在
onRequest中修改类静态属性来“传递”数据给onMessage,下次请求可能拿到脏值 - 如果要用 Redis,建议用连接池(如
co\Redis+Swoole\Coroutine\Pool),别用单例长连接,容易超时或阻塞 - 日志写入必须加锁或走异步队列,否则并发高时文件写乱序
-
onRequest执行时间应尽量短(
真正容易被忽略的是:onRequest 的生命周期和 HTTP 请求完全绑定,而 WebSocket 连接可能存活数小时。一旦你把连接状态缓存逻辑写错(比如忘了在 onClose 清表),后续所有主动推送都会失效,且很难排查——因为错误不报异常,只是静默丢消息。

















