Laravel Reverb如何在后端实时获取用户上下线状态?求最佳实践
WebSocket网页游戏用户在线/离线状态管理最佳实践
针对你遇到的问题,以下是基于Laravel Reverb + Echo的可靠解决方案,完全规避客户端主动上报的不可靠性:
1. 放弃客户端AJAX上报,依赖Reverb内置连接检测
Reverb作为WebSocket服务器,本身会自动管理连接生命周期:
- 当用户正常断开(比如关闭页面),Reverb后端会同步触发用户离开频道的事件;
- 当用户意外断开(浏览器崩溃、网络中断),Reverb通过内置的ping-pong机制检测到死连接后,会自动清理该用户的频道成员身份,并触发后端断开事件,无需客户端任何操作。
2. 监听后端事件更新用户状态
在Laravel中,Reverb会针对Presence频道触发两个核心事件,你可以通过监听这些事件来维护用户在线状态:
注册事件监听
在app/Providers/EventServiceProvider.php中添加事件与监听器的绑定:
use Illuminate\Broadcasting\Events\UserJoined; use Illuminate\Broadcasting\Events\UserLeft; protected $listen = [ UserJoined::class => [ \App\Listeners\MarkUserOnline::class, ], UserLeft::class => [ \App\Listeners\MarkUserOffline::class, ], ];
实现监听器逻辑
创建对应的监听器来更新用户状态(示例用Redis+数据库双存储,兼顾性能与持久化):
// app/Listeners/MarkUserOnline.php namespace App\Listeners; use Illuminate\Broadcasting\Events\UserJoined; use Illuminate\Support\Facades\Redis; class MarkUserOnline { public function handle(UserJoined $event) { // 用Redis存储实时在线状态(高性能) Redis::setex("user:{$event->user->id}:online", 300, true); // 更新数据库状态(持久化,可选) $event->user->update(['is_online' => true]); } }
// app/Listeners/MarkUserOffline.php namespace App\Listeners; use Illuminate\Broadcasting\Events\UserLeft; use Illuminate\Support\Facades\Redis; class MarkUserOffline { public function handle(UserLeft $event) { Redis::del("user:{$event->user->id}:online"); $event->user->update(['is_online' => false]); } }
3. 优化Reverb的ping-pong配置
调整Reverb的连接超时参数,确保及时检测死连接。在config/reverb.php中修改:
return [ // ... 'ping_interval' => env('REVERB_PING_INTERVAL', 30), // 每30秒发送一次ping 'timeout' => env('REVERB_TIMEOUT', 60), // 60秒未收到pong则判定连接断开 // ... ];
这个配置平衡了实时性与服务器负载,可根据你的游戏并发量调整。
4. 获取实时在线用户列表
有两种可靠方式获取在线用户:
- 从Presence频道直接获取:如果用户都在同一个游戏房间频道,可直接通过后端API获取频道成员:
use Illuminate\Support\Facades\Broadcast; $onlineUsers = Broadcast::channel('game-room-123')->users(); - 从Redis查询:如果需要全局在线用户列表,可通过Redis的set集合查询(建议用set存储用户ID,查询更高效)。
内容的提问来源于stack exchange,提问作者Russell
相关产品推荐
相关产品推荐

