workerman 原生不支持 php 的 $_session,需手动通过 $connection->session 存储连接级状态,跨进程共享须用 redis 等外部存储,并注意登录/退出/断连时的 session 清理。

Workerman 里没有内置 session,$_SESSION 用不了
Workerman 是常驻内存的长连接服务,PHP 的传统 $_SESSION 依赖于 CGI/FPM 的每次请求初始化 + 文件/Redis 存储,而 Workerman 不走 PHP-FPM,session_start() 调用会失败或无效,直接读写 $_SESSION 拿到的是空数组或报错。
常见错误现象:Undefined index: user_id、session_start(): Failed to initialize storage module、多次请求间数据完全不共享。
- 别在
onMessage里调用session_start()—— 它不会生效,还可能干扰后续逻辑 - 不要试图复用 Apache/Nginx 下的 session 文件路径,Workerman 进程无自动 session 生命周期管理
- 如果用了
think-swoole或hyperf等框架封装层,注意它们是否已帮你做了 session 抽象;纯 Workerman 原生必须自己管
用 $connection->session 手动挂载用户状态最直接
Workerman 允许你往 $connection 对象上任意挂属性,$connection->session 是社区约定俗成的命名方式(非内置 API),本质就是个普通对象属性,用于存储该连接对应的用户上下文。
使用场景:登录后绑定用户 ID、记录客户端类型、保存临时 token 验证状态、区分 WebSocket 多房间订阅关系。
- 登录成功后立即赋值:
$connection->session = ['user_id' => 123, 'role' => 'admin']; - 后续所有
onMessage回调里,直接读取:$user_id = $connection->session['user_id'] ?? null; - 注意判空 —— 连接刚建立时
$connection->session是null,不能直接当数组访问 - 不建议存大对象或资源句柄(如 PDO 实例),只放轻量标识和简单结构化数据
需要跨进程共享?得用外部存储 + 自定义 key
单个 Workerman 进程内用 $connection->session 没问题,但如果你开了多个 worker 进程(比如 'worker_num' => 4),不同连接可能落在不同进程里,此时仅靠内存属性无法互通。要实现“同一个用户在不同连接间状态一致”,必须引入外部存储。
典型做法是:用用户唯一标识(如 token、client_id)作为 key,把 session 数据存在 Redis 中。
- 登录成功后写入:
$redis->setex('sess:' . $token, 3600, json_encode(['user_id' => 123])); - 每次收到消息时查一次:
$data = json_decode($redis->get('sess:' . $token), true); - key 命名要有业务前缀和过期控制,避免键冲突和无限堆积
- 别在每次
onMessage都新建 Redis 连接 —— 应该复用全局连接实例,否则性能崩得很快
WebSocket 场景下怎么维持 sessionId?靠首次握手传参
HTTP 协议有 Cookie 天然带 session ID,但 WebSocket 握手是一次性 HTTP 请求,之后就升级为二进制帧通信,不再自动携带 Cookie(除非客户端显式配置)。所以你要自己把标识传进来。
常见方式是在 WebSocket URL 后加参数,比如 ws://example.com:2346?token=abc123,然后在 onConnect 里解析。
- Workerman 提供了
$connection->getRemoteIp()和$connection->http_header,但 URL 参数得从$connection->context->uri或$connection->http_header['cookie']里手动提取 - 推荐用 query string 传参,比解析 Cookie 更稳定(尤其跨域时 Cookie 可能被浏览器拦截)
- 解析示例:
parse_str(parse_url($connection->context->uri, PHP_URL_QUERY), $query); $token = $query['token'] ?? ''; - 千万别把敏感字段(如密码、原始 token)明文塞进 URL,应提前换为短期有效的单次凭证
真正麻烦的从来不是“怎么存”,而是“什么时候清”——用户退出、token 过期、连接异常断开,这些情况下的 session 清理很容易漏掉,一不留神就积累一堆僵尸状态。









