什么是广播
WebSocket 让服务器可以实时向客户端推送数据。
Laravel 的广播用于把服务端事件通过 WebSocket 送达前端 JavaScript。
例如订单状态发生变化时,浏览器无需刷新即可立即看到更新。
Laravel 广播的优势在于:服务器端的事件名与数据可以直接分享给客户端。
广播基于 Laravel 事件系统。建议先了解事件与监听器的基础。
新项目默认关闭广播。用 install:broadcasting 启用:
php artisan install:broadcasting
命令会提示你选择要使用的广播服务,并生成 config/broadcasting.php 与 routes/channels.php。
Laravel Reverb
Laravel 11 及以后推荐使用官方 WebSocket 服务器 Laravel Reverb。
Reverb 支持自托管,无需外部服务即可实现实时通信。
在 install:broadcasting 加 --reverb 可一次完成 Composer / NPM 依赖安装与 .env 配置:
php artisan install:broadcasting --reverb
手动安装:
composer require laravel/reverb
php artisan reverb:install
.env 主要配置
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
启动 Reverb 服务器
生产环境请使用 Supervisor 等进程管理工具以守护方式运行。
广播事件通过队列处理,除 Reverb 外还需启动队列 worker:
创建广播事件
生成事件类
php artisan make:event OrderShipmentStatusUpdated
给事件类实现 ShouldBroadcast 接口:
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public function __construct(
public Order $order,
) {}
/** 返回要广播到的频道 */
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.' . $this->order->id);
}
}
只要实现 ShouldBroadcast,事件触发时就会自动通过队列广播。
自定义广播数据
默认所有 public 属性都会成为广播 payload。若需精简数据,定义 broadcastWith:
public function broadcastWith(): array
{
return [
'order_id' => $this->order->id,
'status' => $this->order->status,
];
}
自定义广播名称
默认使用类名作为事件名。可用 broadcastAs 自定义:
public function broadcastAs(): string
{
return 'order.status.updated';
}
前端监听时使用 . 前缀以关闭 Laravel 命名空间前缀:
Echo.private(`orders.${orderId}`)
.listen('.order.status.updated', (e) => {
console.log(e);
});
频道类型
| 频道 | 类 | 说明 |
|---|
| Public | Channel | 无需认证,任何人都可订阅 |
| Private | PrivateChannel | 仅认证用户,需要授权逻辑 |
| Presence | PresenceChannel | Private 的扩展,可获取参与者列表 |
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
// Public
public function broadcastOn(): Channel
{
return new Channel('posts');
}
// Private
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.' . $this->order->id);
}
// Presence
public function broadcastOn(): Channel
{
return new PresenceChannel('rooms.' . $this->room->id);
}
广播到多个频道用数组返回:
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.' . $this->order->id),
new Channel('admin.orders'),
];
}
频道授权
Private 与 Presence 频道在订阅前会在服务器端进行授权。
routes/channels.php
在 install:broadcasting 生成的 routes/channels.php 中定义授权回调:
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
回调第一个参数是当前用户,之后是频道名中的通配符。
返回 true 或 truthy 值表示授权通过,false 则拒绝。
也可使用路由模型绑定。将频道名写为 orders.{order},回调会得到 Order 实例。
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
return $user->id === $order->user_id;
});
使用频道类做授权
频道多时可用频道类组织:
php artisan make:channel OrderChannel
<?php
namespace App\Broadcasting;
use App\Models\Order;
use App\Models\User;
class OrderChannel
{
public function join(User $user, Order $order): bool
{
return $user->id === $order->user_id;
}
}
在 routes/channels.php 中注册:
use App\Broadcasting\OrderChannel;
Broadcast::channel('orders.{order}', OrderChannel::class);
触发事件
ShouldBroadcast 事件与普通事件的触发方式相同:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);
只广播给他人(排除自己):
broadcast(new OrderShipmentStatusUpdated($order))->toOthers();
使用 toOthers 需要事件类 use InteractsWithSockets trait。
前端接收
配置 Laravel Echo
若使用 Reverb,在 resources/js/bootstrap.js 中设置 Echo:
npm install --save-dev laravel-echo pusher-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'],
});
监听事件
// Public
Echo.channel('posts')
.listen('PostPublished', (e) => {
console.log(e.post);
});
// Private
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order);
});
// Presence
Echo.join(`rooms.${roomId}`)
.here((users) => {
console.log('当前成员:', users);
})
.joining((user) => {
console.log(user.name, '加入了');
})
.leaving((user) => {
console.log(user.name, '离开了');
})
.listen('MessagePosted', (e) => {
console.log(e.message);
});
使用 React / Vue Hook
若使用官方 React / Vue 启动套件,可用专用 hook:
import { useEcho } from "@laravel/echo-react";
// Private
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// Public
import { useEchoPublic } from "@laravel/echo-react";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});
useEcho 会在组件卸载时自动离开频道。
前端构建前请确认 .env 中的 VITE_REVERB_* 已正确设置。
实战示例:订单状态实时更新
启用广播
php artisan install:broadcasting --reverb
启动 Reverb 服务器与队列 worker:php artisan reverb:start
php artisan queue:work
创建事件类
php artisan make:event OrderShipmentStatusUpdated
编辑 app/Events/OrderShipmentStatusUpdated.php:<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public function __construct(
public Order $order,
) {}
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.' . $this->order->id);
}
public function broadcastWith(): array
{
return [
'order_id' => $this->order->id,
'status' => $this->order->status,
];
}
}
定义频道授权
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
return $user->id === $order->user_id;
});
触发事件
use App\Events\OrderShipmentStatusUpdated;
$order->update(['status' => 'shipped']);
OrderShipmentStatusUpdated::dispatch($order);
前端监听
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (e) => {
document.getElementById('status').textContent = e.status;
});
下一步
Laravel Reverb
查看 Reverb 服务器的部署、生产运维与扩展详情。
队列与任务
广播依赖队列处理。了解队列的配置与运维。
事件与监听器
学习作为广播基础的 Laravel 事件系统。