Laravel 广播系统与实时功能

在现代 Web 应用中,实时功能(如聊天、通知、动态数据更新)已成为标配。Laravel 的广播系统(Broadcasting)允许你使用 WebSocket 技术将服务器端的事件实时推送到前端,构建出响应迅速、交互流畅的实时应用。本章将带你掌握广播系统的配置、事件定义、频道授权以及前端集成。

⚡ 核心价值: 广播系统让你无需轮询即可将数据实时推送给客户端,结合 PusherRedis + Socket.IO,可以轻松实现聊天室、实时通知、在线状态等功能。

1. 广播系统简介

Laravel 广播系统允许你在服务器端触发事件,并通过 WebSocket 将这些事件广播到客户端。它支持两种主要的广播驱动:

  • Pusher Channels – 云服务,无需自己维护 WebSocket 服务器。
  • Redis – 配合 socket.iolaravel-websockets 包自建 WebSocket 服务器。

广播的事件需要实现 ShouldBroadcast 接口,Laravel 会自动将事件数据推送到指定的频道。

2. 配置广播驱动

广播配置文件位于 config/broadcasting.php。你需要设置 BROADCAST_DRIVER 环境变量,并配置对应驱动的凭据。

Pusher 配置示例


BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=mt1
                    

安装 Pusher PHP SDK:


composer require pusher/pusher-php-server
                    

Redis 配置示例


BROADCAST_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
                    

使用 Redis 驱动时,你需要一个 WebSocket 服务器来处理广播,例如 laravel-websockets 包:


composer require beyondcode/laravel-websockets
                    

3. 创建广播事件

生成一个事件类并实现 ShouldBroadcast 接口:


php artisan make:event NewMessage
                    

在事件类中,你需要指定广播的频道名称(broadcastOn 方法)以及可选的数据(broadcastWith)。


<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class NewMessage implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct($message)
    {
        $this->message = $message;
    }

    // 指定广播频道(可以是字符串或 Channel 实例)
    public function broadcastOn()
    {
        return new Channel('chat');
    }

    // 自定义广播数据(默认会序列化所有 public 属性)
    public function broadcastWith()
    {
        return ['message' => $this->message, 'time' => now()->toDateTimeString()];
    }

    // 可选:指定广播队列连接
    public function broadcastQueue()
    {
        return 'broadcast';
    }
}
                    

4. 触发广播事件

在控制器或其他地方,使用 event() 函数触发事件,广播将自动进行(如果驱动已配置):


use App\Events\NewMessage;

event(new NewMessage('Hello, world!'));
                    

5. 频道与授权

Laravel 支持三种频道类型:公共频道(public)私有频道(private)存在频道(presence)。私有频道和存在频道需要用户认证。

公共频道

任何用户都可以订阅,无需授权。在 broadcastOn 中返回 new Channel('channel-name')

私有频道

只有授权用户才能订阅。频道名称以 private- 开头,并在 routes/channels.php 中定义授权回调。


// 在事件中
public function broadcastOn()
{
    return new PrivateChannel('user.' . $this->user->id);
}
                    

routes/channels.php 中授权:


Broadcast::channel('user.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});
                    

存在频道

私有频道的扩展,除了订阅外,还能获取频道内其他用户的信息。频道名以 presence- 开头,授权回调需要返回用户信息数组。


// 事件中
public function broadcastOn()
{
    return new PresenceChannel('chat.' . $this->chatId);
}
                    

授权回调:


Broadcast::channel('chat.{chatId}', function ($user, $chatId) {
    // 验证用户是否属于该聊天室
    if ($user->canJoinChat($chatId)) {
        return ['id' => $user->id, 'name' => $user->name];
    }
    return false;
});
                    

6. 前端集成:Laravel Echo

Laravel Echo 是一个 JavaScript 库,用于订阅频道和监听事件。安装依赖:


npm install --save-dev laravel-echo pusher-js
                    

或者使用 Redis + Socket.io:


npm install --save-dev laravel-echo socket.io-client
                    

初始化 Echo(Pusher 示例)


import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    forceTLS: true,
});
                    

监听事件


// 公共频道
window.Echo.channel('chat')
    .listen('NewMessage', (e) => {
        console.log(e.message);
    });

// 私有频道(需要认证)
window.Echo.private('user.' + userId)
    .listen('NewMessage', (e) => {
        console.log(e.message);
    });

// 存在频道
window.Echo.join('chat.' + chatId)
    .here((users) => {
        console.log('当前在线用户:', users);
    })
    .joining((user) => {
        console.log('用户加入:', user);
    })
    .leaving((user) => {
        console.log('用户离开:', user);
    })
    .listen('NewMessage', (e) => {
        console.log(e.message);
    });
                    

7. 身份验证路由

对于私有频道和存在频道,前端需要向服务器请求授权。Laravel 提供了 /broadcasting/auth 路由来处理授权。确保在 routes/api.phproutes/channels.php 中已启用。

如果你使用 Laravel Sanctum 或 Passport 进行 API 认证,需要在前端请求中包含认证令牌,Echo 会自动处理。

8. 使用 Laravel Websockets 自建 WebSocket 服务器

laravel-websockets 包让你可以在本地或服务器上运行 WebSocket 服务器,无需依赖 Pusher。安装后发布配置文件:


php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
                    

修改 .env


BROADCAST_DRIVER=pusher
PUSHER_APP_ID=local
PUSHER_APP_KEY=local
PUSHER_APP_SECRET=local
PUSHER_APP_CLUSTER=local
                    

启动 WebSocket 服务器:


php artisan websockets:serve
                    

前端 Echo 配置时,将 wsHostwsPort 指向你的服务器地址。

9. 最佳实践与注意事项

  • 选择驱动: 小型项目推荐 Pusher(简单快捷),大型项目或自托管可选择 Redis + laravel-websockets。
  • 使用队列: 广播事件会推送到队列(如果配置了队列驱动),避免阻塞 HTTP 请求。
  • 频道命名规范: 使用点号分隔命名空间,如 user.{id}chat.{chatId}
  • 授权回调的性能: 确保授权回调中的查询高效,避免复杂逻辑。
  • 处理连接断开: 前端应监听 disconnect 事件并实现重连机制。
  • 安全性: 私有频道和存在频道必须严格授权,避免信息泄露。
📖 官方文档: Laravel BroadcastingLaravel Echo 提供了更全面的指南。

10. 总结

Laravel 的广播系统让你能够轻松构建实时 Web 应用。通过配置驱动、定义广播事件、授权频道以及前端集成,你可以快速实现聊天、实时通知、在线用户列表等功能。结合队列和自建 WebSocket 服务器,甚至可以扩展到大规模实时应用。