You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 07:23:11