Laravel Websockets是Laravel生态中常用的实时通信方案,基于Pusher协议实现,默认提供了基础的连接处理能力。但在实际业务场景中,我们往往需要自定义连接建立、断开、重连等全流程逻辑,同时需要对连接的状态进行持久化或临时存储,方便后续业务调用。

Laravel Websockets连接生命周期核心事件
Laravel Websockets的连接生命周期由一系列事件驱动,我们可以通过监听这些事件来插入自定义逻辑。核心事件包含连接建立前、连接建立后、连接断开、订阅频道、取消订阅频道等。
事件监听配置方式
我们可以在EventServiceProvider中注册对应的事件监听器,首先定义监听器类:
<?php
namespace AppListeners;
use BeyondCodeLaravelWebSocketsEventsWebSocketConnectionEstablished;
use BeyondCodeLaravelWebSocketsEventsWebSocketConnectionClosed;
class WebsocketConnectionListener
{
/**
* 处理连接建立事件
*/
public function handleConnectionEstablished(WebSocketConnectionEstablished $event)
{
$connection = $event->connection;
$appId = $event->appId;
// 自定义连接建立后的逻辑,比如记录连接信息
Log::info('websocket连接建立', [
'connection_id' => $connection->id,
'app_id' => $appId,
'connect_time' => now()->toDateTimeString()
]);
}
/**
* 处理连接断开事件
*/
public function handleConnectionClosed(WebSocketConnectionClosed $event)
{
$connection = $event->connection;
// 自定义连接断开后的逻辑,比如清理连接状态
Log::info('websocket连接断开', [
'connection_id' => $connection->id,
'disconnect_time' => now()->toDateTimeString()
]);
}
}
然后在EventServiceProvider的$listen数组中注册事件和监听器的对应关系:
<?php
namespace AppProviders;
use IlluminateFoundationSupportProvidersEventServiceProvider as ServiceProvider;
use BeyondCodeLaravelWebSocketsEventsWebSocketConnectionEstablished;
use BeyondCodeLaravelWebSocketsEventsWebSocketConnectionClosed;
use AppListenersWebsocketConnectionListener;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
WebSocketConnectionEstablished::class => [
WebsocketConnectionListener::class . '@handleConnectionEstablished'
],
WebSocketConnectionClosed::class => [
WebsocketConnectionListener::class . '@handleConnectionClosed'
],
];
}
连接状态管理实践方案
连接状态管理需要区分临时状态和持久化状态,临时状态可以存储在内存中,持久化状态需要存入数据库或缓存中。
临时状态存储(基于内存)
我们可以使用单例类来管理当前进程内的连接状态,适合单机部署的场景:
<?php
namespace AppServices;
use BeyondCodeLaravelWebSocketsWebSocketConnection as WebSocketConnection;
class ConnectionStateManager
{
// 存储连接ID到状态的映射
protected static $connectionStates = [];
/**
* 设置连接状态
*/
public static function setState(string $connectionId, array $state)
{
static::$connectionStates[$connectionId] = $state;
}
/**
* 获取连接状态
*/
public static function getState(string $connectionId)
{
return static::$connectionStates[$connectionId] ?? null;
}
/**
* 移除连接状态
*/
public static function removeState(string $connectionId)
{
unset(static::$connectionStates[$connectionId]);
}
/**
* 绑定连接到用户
*/
public static function bindConnectionToUser(string $connectionId, int $userId)
{
$state = static::getState($connectionId) ?? [];
$state['user_id'] = $userId;
static::setState($connectionId, $state);
}
}
在之前的连接事件监听器中调用状态管理类:
// 连接建立时初始化状态
public function handleConnectionEstablished(WebSocketConnectionEstablished $event)
{
$connection = $event->connection;
ConnectionStateManager::setState($connection->id, [
'status' => 'connected',
'connect_time' => now()->getTimestamp(),
'user_id' => null
]);
}
// 连接断开时清理状态
public function handleConnectionClosed(WebSocketConnectionClosed $event)
{
$connection = $event->connection;
ConnectionStateManager::removeState($connection->id);
}
持久化状态存储(基于Redis)
如果是多机部署的场景,需要使用共享存储来保存连接状态,这里以Redis为例:
<?php
namespace AppServices;
use IlluminateSupportFacadesRedis;
class RedisConnectionStateManager
{
protected $prefix = 'ws:connection:';
/**
* 设置连接状态
*/
public function setState(string $connectionId, array $state, int $ttl = 3600)
{
$key = $this->prefix . $connectionId;
Redis::setex($key, $ttl, json_encode($state));
}
/**
* 获取连接状态
*/
public function getState(string $connectionId)
{
$key = $this->prefix . $connectionId;
$data = Redis::get($key);
return $data ? json_decode($data, true) : null;
}
/**
* 移除连接状态
*/
public function removeState(string $connectionId)
{
$key = $this->prefix . $connectionId;
Redis::del($key);
}
/**
* 根据用户ID获取所有连接ID
*/
public function getConnectionsByUserId(int $userId)
{
$pattern = $this->prefix . '*';
$keys = Redis::keys($pattern);
$result = [];
foreach ($keys as $key) {
$state = json_decode(Redis::get($key), true);
if ($state && ($state['user_id'] ?? 0) == $userId) {
$result[] = str_replace($this->prefix, '', $key);
}
}
return $result;
}
}
自定义连接鉴权逻辑
除了生命周期事件,我们还可以自定义连接的鉴权逻辑,限制非法连接。可以在config/websockets.php中配置自定义的鉴权类:
// config/websockets.php
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('PUSHER_APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
// 自定义鉴权类
'auth_class' => AppServicesCustomWebsocketAuth::class,
],
],
自定义鉴权类需要实现BeyondCodeLaravelWebSocketsContractsAppAuth接口:
<?php
namespace AppServices;
use BeyondCodeLaravelWebSocketsContractsAppAuth;
use BeyondCodeLaravelWebSocketsAppsApp;
use IlluminateHttpRequest;
class CustomWebsocketAuth implements AppAuth
{
public function authenticate(App $app, Request $request): bool
{
// 自定义鉴权逻辑,比如校验token
$token = $request->input('token');
if (empty($token)) {
return false;
}
// 这里可以调用用户服务校验token有效性
$isValid = AppServicesUserService::verifyToken($token);
if ($isValid) {
// 鉴权通过后可以绑定用户到连接
$connectionId = $request->input('connection_id');
ConnectionStateManager::bindConnectionToUser($connectionId, $isValid['user_id']);
}
return $isValid !== false;
}
}
常见问题与注意事项
- 连接断开事件可能因为网络异常无法触发,需要设置状态过期时间,定期清理无效状态
- 多机部署时不要使用内存存储连接状态,避免状态不一致
- 自定义事件监听时不要执行耗时操作,避免阻塞WebSocket连接处理流程
- 状态存储的键名需要做好命名规范,避免和其他缓存键冲突
通过以上方式,我们可以完整定制Laravel Websockets的连接生命周期,同时实现灵活的连接状态管理,满足不同业务场景下的实时通信需求。
LaravelWebsockets连接生命周期状态管理Pusher修改时间:2026-07-12 02:33:32