如何用Laravel+Socket.io实现跨页面的实时事件推送与同步?
Laravel 掷骰子游戏跨页面实时同步实现方案

技术选型
跨页面实时同步依赖服务端主动推送,Laravel生态优先用原生工具栈实现,无需引入冗余第三方服务:
- 服务端推送用 Laravel Reverb,Laravel 10+ 版本官方原生支持的WebSocket服务,无需额外部署Node.js服务
- 前端监听用 Laravel Echo 配合原生JS实现,适配所有页面的公共逻辑
具体实现步骤
1. 服务端配置
- 安装Reverb依赖:
composer require laravel/reverb --with-all-dependencies - 自动生成配置项:
php artisan reverb:install - 修改
.env配置,设置广播驱动为Reverb:BROADCAST_CONNECTION=reverb - 新建骰子状态广播事件:
php artisan make:event DiceStateUpdated
编辑事件类,实现公共频道广播逻辑:
// app/Events/DiceStateUpdated.php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PublicChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class DiceStateUpdated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct( public string $state, // rolling=转动中 finished=转动结束 public int $diceValue, // 最终点数,转动中传0即可 public int $timestamp = 0 ) { $this->timestamp = now()->timestamp; } public function broadcastOn(): Channel { return new PublicChannel('dice-game'); } }
2. 掷骰子接口逻辑改造
在原有的掷骰子请求接口中,分两次广播事件,同步状态到所有页面:
// routes/web.php 或 routes/api.php Route::post('/roll-dice', function () { // 广播转动开始事件,触发所有页面的转动动画 event(new DiceStateUpdated('rolling', 0)); // 等待时长和前端骰子动画时长对齐,这里设1.5秒 usleep(1500000); // 生成随机点数 $finalValue = rand(1, 6); // 广播转动结束事件,同步最终点数到所有页面 event(new DiceStateUpdated('finished', $finalValue)); return response()->json(['dice_value' => $finalValue]); });
3. 前端全局监听配置
在站点所有页面引入的公共JS文件中,配置Laravel Echo并全局监听广播事件:
// 公共JS文件,比如 resources/js/app.js import Echo from 'laravel-echo'; import Pusher from 'pusher-js'; window.Pusher = Pusher; window.Echo = new Echo({ broadcaster: 'reverb', key: import.meta.env.VITE_REVERB_APP_KEY, wsHost: import.meta.env.VITE_REVERB_HOST, wsPort: import.meta.env.VITE_REVERB_PORT ?? 80, wssPort: import.meta.env.VITE_REVERB_PORT ?? 443, forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https', enabledTransports: ['ws', 'wss'], }); // 全局监听骰子状态事件 window.Echo.channel('dice-game') .listen('DiceStateUpdated', (event) => { if(event.state === 'rolling') { // 调用当前页面封装的骰子转动动画方法 startDiceAnimation(); } else if(event.state === 'finished') { // 停止转动动画,展示最终点数 stopDiceAnimation(event.diceValue); } });
注意:如果前端收不到广播事件,可以在事件类中添加自定义事件名的方法:
public function broadcastAs(): string { return 'dice.state.update'; }前端监听时事件名前加
.即可:.listen('.dice.state.update', () => {})
4. 运行部署
- 本地调试时启动Reverb服务:
php artisan reverb:start - 正式上线用Supervisor守护Reverb进程即可,配置规则和Laravel队列的守护规则一致。
轻量备选方案(无WebSocket)
如果站点访问量不大,不想额外维护WebSocket服务,可以用短轮询方案实现:
- 服务端把最新的骰子状态、点数、更新时间戳存在Redis缓存中
- 所有页面每隔1秒请求一次通用接口拉取最新状态,和本地存储的时间戳对比,有更新就触发对应动画和展示
该方案实现成本更低,1秒的延迟对于掷骰子游戏的体验几乎没有影响。
内容的提问来源于stack exchange,提问作者Maulik Chodvadiya
相关产品推荐
相关产品推荐

