websocket连接建立时的get参数只能在onconnect回调中通过解析$connection->context->websocket->handshake['requestline']获取,因websocket协议不创建http\request实例,$request->get()无效;需用parse_url和parse_str提取并存至$connection属性供后续使用。

WebSocket 连接建立时的 GET 参数,只能在 onConnect 回调里拿到,且必须从 $connection->getRemoteIp() 之外的源头解析——它藏在 $connection->context->host 或更准确地说,是 $connection->context->websocket->handshake 的原始请求头里。
为什么 $request->get() 在 WebSocket 里完全无效
Workerman 的 WebSocket 协议处理器(Workerman\Protocols\Websocket)不构造 Request 对象,也不触发 HTTP 协议层的参数解析逻辑。$request->get() 是 HTTP 协议专用方法,只存在于 Workerman\Protocols\Http\Request 实例中。WebSocket 连接握手阶段虽用的是 HTTP Upgrade 请求,但 Workerman 不会把它升级为一个可调用 get() 的 Request 实例。
常见错误现象:
在 onMessage 里写 $request->get('token') → 报错 Undefined variable: $request;
或误以为 $connection 有 get() 方法 → 调用失败,返回 null 或致命错误。
- WebSocket 连接对象
$connection是Workerman\Connection\TcpConnection实例,不是Request -
onMessage收到的是纯消息体(字符串或二进制),没有 URL 查询参数上下文 - GET 参数只存在于 TCP 握手那一刻的 HTTP 请求行和头中,之后就丢了
onConnect 中手动解析 handshake 原始数据
Workerman 会在 WebSocket 握手完成后,把原始 HTTP 请求头存入 $connection->context->websocket->handshake(类型为 array),其中 requestLine 字段包含完整的请求行,例如:GET /ws?token=abc123&uid=456 HTTP/1.1。
实操建议:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 只在
onConnect回调里处理,错过就永远拿不到 - 用
parse_url()+parse_str()安全提取,别直接正则匹配requestLine - 注意:
$connection->context可能为 null,需先判空 - 示例代码片段:
use Workerman\Worker;
$ws_worker = new Worker('websocket://0.0.0.0:2346');
$ws_worker->onConnect = function ($connection) {
if (isset($connection->context->websocket->handshake['requestLine'])) {
$line = $connection->context->websocket->handshake['requestLine'];
$url = parse_url($line);
if (isset($url['query'])) {
parse_str($url['query'], $query);
$token = $query['token'] ?? null;
$uid = (int)($query['uid'] ?? 0);
// 存到连接上下文中,供 onMessage 后续使用
$connection->token = $token;
$connection->uid = $uid;
}
}
};
如何在 onMessage 里安全复用这些参数
不能重新解析 handshake(它只在 onConnect 时存在),必须提前存到 $connection 实例属性上。这是唯一可靠方式。
- 存的时候不校验 token 有效性?可以,但建议在
onConnect就做基础校验(如非空、长度、格式),避免无效连接占资源 - 如果 token 需要 Redis 校验或 DB 查询,不要在
onConnect里同步执行——会阻塞整个进程;应改用异步方式(如Worker::sendToWorkerProcess()或协程 client) - 注意:多进程模式下,
$connection属性只在本进程有效;跨进程广播时,需通过 GatewayWorker 的 Events 或 Channel 传递 uid/token - 别把敏感参数(如 token)直接 echo 给前端,或记录到日志明文字段中
用 Nginx 代理时 GET 参数会不会丢失
会,如果 Nginx 配置没透传原始请求路径。默认 proxy_pass 会重写 URI,丢掉 query string。
必须显式配置:
location /ws {
proxy_pass http://127.0.0.1:2346;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 关键:保留原始 URI,包括 ? 后面的部分
proxy_redirect off;
proxy_set_header Host $host;
}
否则浏览器连 wss://example.com/ws?token=xxx,后端收到的 requestLine 可能变成 GET / HTTP/1.1,参数彻底消失。
真正容易被忽略的点是:即使你写了 proxy_pass http://127.0.0.1:2346/(结尾带斜杠),Nginx 也会 strip 掉原始 query —— 必须去掉末尾斜杠,或用 rewrite 显式携带 $args。









