如何在Laravel中监听Whisper事件并将客户端消息存入数据库?
解决Laravel Echo发送消息到服务器并存入数据库的问题
首先明确:whisper 是Laravel Echo用于客户端之间点对点/房间内实时通信的方法,消息会经Redis中转,但Laravel服务器默认不会监听这类whisper消息。要实现消息存入数据库,有两种可行方案:
方案一:监听Redis中的whisper频道
whisper发送的消息会被推送到Redis的特定频道,格式为 presence-{roomName}:client-events(私有房间则为 private-{roomName}:client-events)。你可以创建常驻进程监听该频道,收到消息后写入数据库。
步骤:
- 创建Artisan命令监听Redis频道:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Redis; use App\Models\Message; class ListenWhisperMessages extends Command { protected $signature = 'redis:listen-whispers {room}'; protected $description = '监听指定房间的whisper消息并存入数据库'; public function handle() { $room = $this->argument('room'); $channel = "presence-{$room}:client-events"; // 私有房间替换为private-{$room}:client-events Redis::subscribe([$channel], function ($message) { $payload = json_decode($message, true); // 仅处理目标newMsg事件 if ($payload['event'] === 'client-newMsg') { Message::create([ 'user_id' => $payload['data']['userId'], // 需确保客户端传递用户ID 'text' => $payload['data']['text'], 'room' => $this->argument('room') ]); } }); } }
注意:客户端用whisper('newMsg', ...)时,Redis中的事件名会自动添加client-前缀,因此需监听client-newMsg。
- 启动命令:
php artisan redis:listen-whispers room
可借助Supervisor工具保证进程常驻运行。
方案二:改用服务器端事件(更推荐)
既然需求是将消息传给服务器并存库,whisper并非最优选择——它的设计初衷是客户端间通信。更直接的方式如下:
步骤:
- 定义服务器端WebSocket事件:
<?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; use App\Models\Message; class NewMessage implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $message; public function __construct(Message $message) { $this->message = $message; } public function broadcastOn() { return new PresenceChannel('room'); // 对应目标房间频道 } }
- 创建API路由接收客户端消息:
// routes/api.php use App\Models\Message; use App\Events\NewMessage; use Illuminate\Http\Request; Route::post('/send-message', function (Request $request) { $message = Message::create([ 'user_id' => auth()->id(), 'text' => $request->text, 'room' => $request->room ]); // 可选:将消息广播给房间内其他客户端 broadcast(new NewMessage($message))->toOthers(); return response()->json(['success' => true]); });
- 客户端发送请求并存库:
// 发送消息到服务器API axios.post('/api/send-message', { text: "Hello server. i am from client!", room: "room" }).then(response => { console.log('消息已存入数据库'); }); // 可选:监听其他客户端的实时消息 window.Echo.join('room') .listen('NewMessage', (e) => { console.log('收到新消息:', e.message.text); });
内容的提问来源于stack exchange,提问作者H.Rad
相关产品推荐
相关产品推荐

