本文目录导读:

Laravel 广播系统是处理实时事件推送的核心组件,下面从 核心概念 到 典型场景 再到 实战代码 来详细讲解。
核心概念(先理解再使用)
Laravel 广播分三层:
- 服务端事件:
ShouldBroadcast接口的 Event 类 - 频道(Channel):路由规则,决定谁可以监听
- 前端接收:Echo + Pusher/Soketi/WebSocket
关键点:广播不是“推消息给所有人”,而是“推消息给特定频道的订阅者”。
典型使用场景
场景 1:实时通知(最常见的用途)
适用业务:
- 用户收到新私信/评论/关注
- 订单状态变更(已付款 → 已发货)
- 后台审批通知
代码示例:
// 1. 创建事件
php artisan make:event OrderStatusChanged
// 2. 事件类
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderStatusChanged implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $order;
public $oldStatus;
public $newStatus;
public function __construct(Order $order, $oldStatus, $newStatus)
{
$this->order = $order;
$this->oldStatus = $oldStatus;
$this->newStatus = $newStatus;
}
// 3. 定义广播的频道
public function broadcastOn()
{
// 该订单的用户专属私有频道
return new PrivateChannel('orders.' . $this->order->user_id);
}
// 可选:自定义广播名称
public function broadcastAs()
{
return 'status.updated';
}
}
// 4. 在业务逻辑中触发
public function updateOrderStatus(Order $order, $newStatus)
{
$oldStatus = $order->status;
$order->status = $newStatus;
$order->save();
// 触发广播事件(注意:会走队列,需配置 QUEUE_CONNECTION)
event(new OrderStatusChanged($order, $oldStatus, $newStatus));
}
// 5. 定义频道授权(在 routes/channels.php)
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{userId}', function (User $user, $userId) {
return $user->id === (int) $userId || $user->isAdmin();
});
前端接收:
// 使用 Laravel Echo 连接(假设是订单管理页面)
Echo.private(`orders.${userId}`)
.listen('OrderStatusChanged', (e) => {
// e.order, e.newStatus
showToast('您的订单状态已变为:' + e.newStatus);
updateOrderUI(e.order);
});
场景 2:在线协作/实时面板(Presence Channel 在场频道)
适用业务:
- 在线文档(多人编辑,显示谁在线)
- 实时仪表盘(数据监控中心)
- 聊天室/会议系统
代码示例:
// 事件:向在场频道广播谁加入了
class UserJoined implements ShouldBroadcast
{
public $user;
public $roomId;
public function __construct($user, $roomId)
{
$this->user = $user;
$this->roomId = $roomId;
}
public function broadcastOn()
{
// 在场频道需要指定房间 ID
return new PresenceChannel('room.' . $this->roomId);
}
}
授权现场频道:
// routes/channels.php
Broadcast::channel('room.{roomId}', function (User $user, $roomId) {
// 返回当前在线用户信息(数据会暴露给前端)
return $user->toArray();
});
前端监听:
Echo.join(`room.${roomId}`)
.here((users) => {
// 获取当前在线的所有用户列表(初始化面板)
displayOnlineUsers(users);
})
.joining((user) => {
// 当有人加入时
alert(`${user.name} 加入了房间`);
})
.leaving((user) => {
// 当有人离开时
alert(`${user.name} 离开了房间`);
});
场景 3:实时数据同步(直播间/股票行情/游戏)
适用业务:
- 股票价格更新、加密货币行情
- 直播间弹幕/礼物
- 外卖配送员位置实时更新
代码:
class StockPriceUpdated implements ShouldBroadcast
{
use Dispatchable, SerializesModels;
public $symbol;
public $price;
public function __construct($symbol, $price)
{
$this->symbol = $symbol;
$this->price = $price;
}
public function broadcastOn()
{
// 公共频道 - 不需要授权
return new Channel('stocks');
}
public function broadcastWith()
{
return [
'symbol' => $this->symbol,
'price' => $this->price,
'time' => now()->toDateTimeString()
];
}
}
// 前端订阅所有股票数据
Echo.channel('stocks')
.listen('StockPriceUpdated', (data) => {
updateStockChart(data.symbol, data.price);
});
场景 4:任务进度通知(后台长任务)
适用业务:
- 大数据导出/导入
- 视频转码(类似抖音上传后转码)
- 批量邮件发送
代码:
class ExportProgressUpdated implements ShouldBroadcast
{
public $exportId;
public $progress; // 0-100
public function __construct($exportId, $progress)
{
$this->exportId = $exportId;
$this->progress = $progress;
}
public function broadcastOn()
{
return new PrivateChannel('user.' . auth()->id() . '.exports.' . $this->exportId);
}
}
// 在导出 Job 的 handle() 中模拟进度
public function handle()
{
for ($i = 0; $i <= 100; $i += 10) {
$this->processChunk();
// 更新进度
event(new ExportProgressUpdated($this->exportId, $i));
sleep(2); // 模拟长任务
}
}
频道授权策略(重要!)
| 频道类型 | 类名 | 场景 | 是否需授权 |
|---|---|---|---|
| 公共频道 | Channel |
行情、广播通知 | 否 |
| 私有频道 | PrivateChannel |
用户专属消息、订单状态 | 是 |
| 在场频道 | PresenceChannel |
在线状态、实时协作 | 是 + 返回用户信息 |
生产环境配置建议
# .env 推荐配置 BROADCAST_DRIVER=pusher # 或 redis/soketi QUEUE_CONNECTION=redis # 广播事件必须走队列,否则同步执行会卡请求 # 使用 Pusher(第三方云服务) PUSHER_APP_ID=xxxx PUSHER_APP_KEY=xxxx PUSHER_APP_SECRET=xxxx PUSHER_APP_CLUSTER=mt1 # 或使用 Soketi(自建 WebSocket 服务) # BROADCAST_DRIVER=soketi # SOKETI_APP_ID=xxxx # SOKETI_APP_KEY=xxxx # SOKETI_APP_SECRET=xxxx # SOKETI_HOST=127.0.0.1 # SOKETI_PORT=6001
性能优化建议
- 必须用队列:所有 ShouldBroadcast 事件会自动入队,确保
QUEUE_CONNECTION=redis而不是sync。 - 避免广播大对象:
broadcastWith()只返回必要数据,不要传整个 User 模型(可能有密码等)。 - 频道粒度:不要使用全局频道应对百万连接,应拆分子频道(
user.1、user.2)。 - 限流:某些高频事件(如鼠标移动)可 1 秒合并广播一次。
- 监控:使用 Redis 的
MONITOR或 Pusher 控制台看消息频率。
调试技巧
// 测试广播事件 php artisan tinker >>> use App\Events\OrderStatusChanged; >>> event(new OrderStatusChanged(1, 'pending', 'paid'));
前端测试:
// 浏览器控制台
Echo.private('orders.1')
.listen('OrderStatusChanged', (e) => console.log(e));
如果你的业务是 实时性要求高、需要双向通信 的场景,Laravel 广播系统是最佳选择,如果有具体业务场景想咨询怎么做,可以发出来我给你针对性方案。