Codeigniter+Ratchet环境下Memcached Session获取为空问题求助
首先,咱们先聚焦核心问题:你在onOpen里拿不到Memcached的会话数据,大概率是会话Cookie传递不匹配或者会话配置(名称、前缀)和CodeIgniter不一致导致的,和框架迁移到Symfony关系不大,先把这些点排查清楚:
1. 确保WebSocket握手时传递了正确的会话Cookie
Ratchet的SessionProvider依赖HTTP握手阶段传递的会话Cookie来获取对应的数据。如果你的前端是用JavaScript连接WebSocket,需要确保:
- 连接时开启
withCredentials(允许携带Cookie):// 原生WebSocket示例 const socket = new WebSocket('ws://your-server-ip:8080'); socket.withCredentials = true; // 如果用WAMP协议(autobahn.js) const connection = new autobahn.Connection({ url: 'ws://your-server-ip:8080', realm: 'your-realm-name', transports: [{ type: 'websocket', options: { withCredentials: true } }] }); - 如果存在跨域场景,需要在服务器端配置CORS允许携带Cookie,比如在Ratchet的HttpServer前添加CORS处理逻辑:
// 自定义CORS处理组件 $corsHandler = new class implements Ratchet\MessageComponentInterface { public function onOpen(ConnectionInterface $conn) { $headers = $conn->WebSocket->request->getHeaders(); if (isset($headers['Origin'])) { $conn->send('Access-Control-Allow-Origin: ' . $headers['Origin'][0]); } $conn->send('Access-Control-Allow-Credentials: true'); $conn->send('Access-Control-Allow-Methods: GET, POST, OPTIONS'); $conn->send('Access-Control-Allow-Headers: Content-Type'); } public function onMessage(ConnectionInterface $from, $msg) {} public function onClose(ConnectionInterface $conn) {} public function onError(ConnectionInterface $conn, \Exception $e) {} }; // 将CORS组件整合到HttpServer链中 $webServer = new Ratchet\Server\IoServer( new Ratchet\Http\HttpServer( $corsHandler, new Ratchet\Session\SessionProvider( new Ratchet\WebSocket\WsServer( new Ratchet\Wamp\WampServer($pusher) ), $sessionStorage ) ), $webSock );
2. 统一CodeIgniter和Ratchet的会话配置
这是最容易忽略的关键:CodeIgniter的会话默认配置和Symfony的MemcachedSessionHandler默认配置不匹配,导致找不到对应的会话数据。
2.1 统一会话Cookie名称
CodeIgniter默认的会话Cookie名是ci_session,而Symfony的SessionProvider默认用PHPSESSID。你需要修改Ratchet的Session配置,和CodeIgniter保持一致:
// 创建SessionStorage时指定会话名称 $sessionStorage = new Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage( ['name' => 'ci_session'], // 和CodeIgniter的sess_cookie_name配置一致 new Handler\MemcachedSessionHandler($memcached) ); // 传入SessionProvider new Ratchet\Session\SessionProvider( new Ratchet\WebSocket\WsServer( new Ratchet\Wamp\WampServer($pusher) ), $sessionStorage );
同时确认CodeIgniter的config.php配置:$config['sess_cookie_name'] = 'ci_session';
2.2 统一Memcached的会话键前缀
CodeIgniter默认会给Memcached里的会话键加ci_session:前缀,而Symfony的MemcachedSessionHandler默认前缀是sf_sess_。需要修改Handler的前缀:
$sessionHandler = new Handler\MemcachedSessionHandler($memcached, [ 'prefix' => 'ci_session:', // 和CodeIgniter的sess_memcached_key配置一致 ]);
对应CodeIgniter的配置:$config['sess_memcached_key'] = 'ci_session:';
3. 验证会话数据匹配度
做完上面的配置后,你可以在两个地方打印会话ID,确认是否一致:
- 在CodeIgniter的控制器里:
echo $this->session->session_id(); - 在Ratchet的
onOpen里:echo $conn->Session->getId();
如果两个ID一致,说明会话已经正确关联,此时再var_dump($conn->Session->all())应该就能拿到用户数据了。
4. 关联用户ID到连接的实现
当能正常获取会话数据后,就可以把用户ID和WebSocket连接绑定:
public function onOpen(ConnectionInterface $conn) { $this->clients->attach($conn); $userId = $conn->Session->get('user_id'); // 从会话里取用户ID if ($userId) { // 用二维数组存储,支持用户多端登录 $this->userConnections[$userId][] = $conn; echo "User {$userId} connected (resource ID: {$conn->resourceId})\n"; } else { echo "Anonymous connection (resource ID: {$conn->resourceId})\n"; } }
之后要给特定用户发消息时,直接通过$userId找到对应的连接即可。
关于是否迁移到Symfony
目前的问题完全不需要迁移到Symfony就能解决,CodeIgniter和Ratchet+Memcached的组合是可以稳定工作的。除非你的项目后续有更复杂的企业级需求(比如微服务、复杂的会话管理),Symfony的生态会更完善,但当前场景下没必要折腾迁移。
内容的提问来源于stack exchange,提问作者Jianov

