PHP项目Laravel广播系统使用场景

wen PHP项目 3

本文目录导读:

PHP项目Laravel广播系统使用场景

  1. 核心概念(先理解再使用)
  2. 典型使用场景
  3. 频道授权策略(重要!)
  4. 生产环境配置建议
  5. 性能优化建议
  6. 调试技巧

Laravel 广播系统是处理实时事件推送的核心组件,下面从 核心概念典型场景 再到 实战代码 来详细讲解。


核心概念(先理解再使用)

Laravel 广播分三层:

  1. 服务端事件ShouldBroadcast 接口的 Event 类
  2. 频道(Channel):路由规则,决定谁可以监听
  3. 前端接收: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

性能优化建议

  1. 必须用队列:所有 ShouldBroadcast 事件会自动入队,确保 QUEUE_CONNECTION=redis 而不是 sync
  2. 避免广播大对象broadcastWith() 只返回必要数据,不要传整个 User 模型(可能有密码等)。
  3. 频道粒度:不要使用全局频道应对百万连接,应拆分子频道(user.1user.2)。
  4. 限流:某些高频事件(如鼠标移动)可 1 秒合并广播一次。
  5. 监控:使用 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 广播系统是最佳选择,如果有具体业务场景想咨询怎么做,可以发出来我给你针对性方案。

抱歉,评论功能暂时关闭!