作者:Laravel 文档贡献者。本文依据 Laravel 13.x 官方文档 Broadcasting完整正文翻译整理,核对日期为 2026-10-05。原文的 React、Vue、Svelte 同功能示例合并说明,保留各项接口与限制;编辑补充和代码调整均在相关位置标明。
适用范围是 Laravel 13、PHP 8.3 及以上,以及与所选广播驱动相匹配的 Echo 版本。阅读前应了解 Laravel 事件、认证与队列。文中所有命令和代码都只做静态核对,未安装依赖、未启动服务、未连接真实广播平台。

广播解决什么问题
很多应用需要在服务器数据变化后立即更新界面。WebSocket 让服务器通过持续连接推送消息,客户端不必反复轮询。例如,导出 CSV 并发送邮件可能需要数分钟:应用把工作交给队列,在任务完成后广播 App\Events\UserDataExported,浏览器收到事件后显示“导出文件已发送”,用户无需刷新页面。
Laravel 的广播机制让服务端事件和前端 JavaScript 共用事件名称与数据。前端订阅有名称的频道,后端向频道发送事件。事件中的附加数据就是客户端可读取的载荷。当前文档提供 Reverb、Pusher Channels、Ably 和 Mercure 四种服务端驱动;Mercure 使用服务器发送事件(SSE),因此不能把所有驱动都理解为相同的 WebSocket 传输。
频道有不同的访问边界:Channel 是公开频道,任何访问者均可订阅,无需认证或授权;PrivateChannel 要求认证和频道级授权;PresenceChannel 在私有频道基础上增加在线成员信息。订单、用户资料等业务数据应先确定订阅权限,再设计广播内容。
启用广播并选择服务端驱动
新建的 Laravel 应用默认不启用广播。安装命令会询问采用哪种广播服务,生成 config/broadcasting.php 与 routes/channels.php,后者用于注册频道授权规则。
php artisan install:broadcasting
广播配置集中在 config/broadcasting.php。除四种服务驱动外,还有用于本地调试的 log 驱动和用于关闭广播的 null 驱动。普通 ShouldBroadcast 事件通过队列发送,因此必须配置并运行 queue worker;后文的同步接口是显式例外。
命令边界:安装命令会下载 Composer/NPM 依赖、修改应用配置和 .env。下面是供人工采用的命令,不是已执行记录。请在版本控制下检查变更,使用项目锁文件约束依赖,并通过安全配置机制注入真实凭据。Pusher、Ably 等托管平台需要相应账户,可能产生费用;Reverb 可自行托管。
Reverb
自动安装会安装所需 Composer 和 NPM 包,并补充环境变量。
php artisan install:broadcasting --reverb
手动路径则先安装包,再发布配置与环境变量:
composer require laravel/reverb
php artisan reverb:install
服务运行、代理与部署细节请继续参照 Reverb 文档;安装成功本身不代表队列或广播服务器已运行。
Pusher Channels
自动安装命令会询问 Pusher 凭据,安装 PHP 与 JavaScript SDK,并更新 .env。手动方式使用相应 PHP SDK。
# 自动方式
php artisan install:broadcasting --pusher
# 手动方式所需 PHP 包
composer require pusher/pusher-php-server
配置文件已有 Pusher 连接示例。下面的值保留原文的占位性质,必须按实际应用填写:
BROADCAST_CONNECTION=pusher
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"
连接的 options 可配置集群等 Channels 支持的选项。若需端到端加密私有频道,在 Pusher 的 options 中加入:
'encryption_master_key_base64' => env('PUSHER_ENCRYPTION_MASTER_KEY'),
它应保存一个 32 字节密钥的 Base64 表示,原文给出的生成命令是 openssl rand -base64 32。这是秘密材料,不能写进前端 VITE_ 变量或提交到代码库。本次未生成实际密钥。
Ably
原文此处采用 Ably 的 Pusher 兼容模式,必须先在 Ably 应用的 Protocol Adapter Settings 中启用 Pusher 协议。Ably 团队也维护专用 broadcaster 与 Echo 客户端,以使用平台特有功能;采用原生方案时参照 Ably Laravel broadcaster,不要混用两套配置。
# 自动方式
php artisan install:broadcasting --ably
# 手动方式所需 PHP 包
composer require ably/ably-php
BROADCAST_CONNECTION=ably
ABLY_KEY=your-ably-key
真实的 ABLY_KEY 留在服务端。配置中的连接与凭据通过 config/broadcasting.php 读取。
Mercure
本次核对的文档提供自动安装选项,以及手动安装 Symfony Mercure 组件与 JWT 库的方式:
# 自动方式
php artisan install:broadcasting --mercure
# 手动方式
composer require symfony/mercure:^0.8 web-token/jwt-library:^4.1
BROADCAST_CONNECTION=mercure
MERCURE_URL=https://mercure.example.com/.well-known/mercure
MERCURE_PUBLIC_URL=https://mercure.example.com/.well-known/mercure
MERCURE_JWT_SECRET=<your-mercure-jwt-secret>
MERCURE_URL 是 Laravel 发布更新时访问的地址;MERCURE_PUBLIC_URL 是浏览器订阅使用的地址,两者可因网络拓扑而不同。Hub 与应用必须配置一致的 JWT secret。端到端加密私有频道还需要 32 字节的 MERCURE_ENCRYPTION_KEY。尖括号内为待替换说明,不是真实有效凭据。
在浏览器中配置 Laravel Echo
Laravel Echo 负责订阅频道和监听广播。安装向导通常会写入配套前端配置;手动安装时,可以在 resources/js/app.js 初始化。Reverb 和 Pusher 兼容客户端都需要:
npm install --save-dev laravel-echo pusher-js
Reverb 使用 Pusher 协议处理连接、频道与消息;原文要求 laravel-echo 至少为 1.16.0,但这一最低版本说明不能证明后文所有新版 API 在 1.16.0 中都存在。
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'],
});
静态审查补充:该原文示例允许通过环境配置使用明文 ws;有真实业务数据时应配置 TLS/WSS,并按部署要求限制允许的来源。示例中的 app key 与 secret 不是同一概念,所有 VITE_ 值均会进入可公开读取的前端构建产物。
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,
});
在 .env 中提供客户端所需的公开连接参数,不能加入 VITE_PUSHER_APP_SECRET:
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
已有预配置 Pusher 实例时,Echo 可以接受 client,避免重复配置:
const options = {
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true,
};
window.Echo = new Echo({ ...options, client: new Pusher(options.key, options) });
此处相较原文的简短复用示例,编辑补入了集群与 TLS 参数,使它与前述 Pusher 配置一致;仍须核对实际集群。
Ably 的原生 JavaScript 兼容模式同样使用 Pusher 客户端,但连接到 Ably 提供的协议端点:
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443,
disableStats: true,
encrypted: true,
});
VITE_ABLY_PUBLIC_KEY 只取 Ably key 中冒号 : 之前的公开部分,不能把完整 key 交给浏览器。Mercure 的前端只需 laravel-echo,使用:
window.Echo = new Echo({
broadcaster: 'mercure',
host: import.meta.env.VITE_MERCURE_HUB_URL,
});
VITE_MERCURE_HUB_URL="${MERCURE_PUBLIC_URL}"
Mercure 的 host 默认是当前源上的 /.well-known/mercure。React、Vue、Svelte 用户可分别从 @laravel/echo-react、@laravel/echo-vue、@laravel/echo-svelte 导入 configureEcho,再传入 { broadcaster: 'reverb' }、'pusher'、'ably' 或 'mercure';这些封装按所选驱动读取对应配置,也可显式覆盖 key、host、port 等选项。
完成配置后构建前端资源。原文的 Reverb/Pusher 示例使用 npm run build,Ably 示例使用 npm run dev。后者是开发工作流,不能把开发服务器当作生产构建部署。本次没有执行这些脚本;项目内的 npm scripts 也应先检查再运行。
用订单状态构建完整广播链路
设想订单页面显示物流状态,服务端在状态变化时触发 OrderShipmentStatusUpdated。事件需要实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast,并通过 broadcastOn() 返回频道或频道数组。随后照常派发事件,Laravel 就会安排广播任务。
下面把原文分散的订单、载荷和事务示例整合为一个事件类。编辑调整:把订单模型设为受保护属性,使用 broadcastWith() 仅发送订单 ID 与状态;加入 Dispatchable、InteractsWithSockets 和提交后派发接口。假设项目已有 Order 模型且含 id、status、user_id 属性;这些是示例业务结构,需与真实模型对应。
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(protected Order $order) {}
public function broadcastOn(): array
{
return [new PrivateChannel('orders.'.$this->order->id)];
}
public function broadcastWith(): array
{
return [
'order' => [
'id' => $this->order->id,
'status' => $this->order->status,
],
];
}
}
原文也用 ServerCreated 示范相同结构:构造器接收公开的 User $user,broadcastOn() 返回 new PrivateChannel('user.'.$this->user->id)。无论频道名称如何选择,私有性都必须通过实际授权规则落实。
在 routes/channels.php 中绑定订单并核对当前用户的归属:
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;
});
回调的第一个参数是认证用户,后面依次对应频道中的通配参数。原文另一个等价场景先接收整数 $orderId,再用 Order::findOrNew($orderId)->user_id 比较;这里选用原文也支持的模型绑定,避免把查不到的订单当作新对象处理。严格相等比较要求两边 ID 类型一致,应在模型类型转换处统一。
派发事件后,浏览器订阅同一名称的私有频道:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (event) => {
// 用项目的状态更新函数更新该订单。
console.log(event.order.id, event.order.status);
});
日志只是原文演示接收数据的方式,正式业务应接入界面状态管理,并避免记录敏感载荷。频道授权只控制谁能订阅,写订单的 HTTP 接口仍须独立认证、授权与校验。
事件名称、载荷、队列和提交时机
自定义名称和数据
默认广播名称来自事件类名。定义 broadcastAs(): string 可以改成 server.created 等名称;Echo 监听时要加前导句点,写作 .listen('.server.created', callback),避免自动添加应用事件命名空间。
默认情况下,事件的所有公开属性会被序列化为广播载荷。公开的 Eloquent 模型也会成为可发送数据的一部分。broadcastWith(): array 可以显式返回所需字段,例如 return ['id' => $this->user->id];。这不仅控制大小,也使数据暴露范围可审查。不要因频道是私有的就默认整个用户或订单模型都适合发送。
决定队列与广播条件
默认队列连接与队列名称来自 config/queue.php。本次 Laravel 13 文档使用属性配置连接和队列:
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;
#[Connection('redis')]
#[Queue('default')]
class ServerCreated implements ShouldBroadcast
{
// 仍需实现 broadcastOn()。
}
也可以通过 broadcastQueue(): string 返回队列名;如果所有广播事件都使用同一队列,可按 队列文档将 ShouldBroadcast 契约路由到该队列。若明确需要同步广播,用 ShouldBroadcastNow 替换 ShouldBroadcast,它使用 sync 队列,广播耗时与失败会更直接地影响当前请求。
broadcastWhen(): bool 决定是否发送某个事件,例如:
public function broadcastWhen(): bool
{
return $this->order->value > 100;
}
这是业务触发条件,不是频道授权的替代品。
等数据库事务提交
在事务内部派发广播事件时,queue worker 可能在事务提交前取走任务。此时数据库还没有新值,甚至尚不存在刚创建的记录,事件反序列化或查询就可能失败。如果队列连接的 after_commit 为 false,可以让特定事件实现 Illuminate\Contracts\Events\ShouldDispatchAfterCommit,明确等所有打开的数据库事务提交后再派发。前面的整合事件已加上该接口。
编辑补充:“提交后派发”解决读取未提交数据的时序问题,不等同于消息必达、严格顺序或业务幂等保证;本文没有验证跨服务故障恢复。客户端在重连后如何获取最新状态仍属于应用设计的一部分。
把频道授权落实到应用
Echo 在订阅私有频道时自动向 Laravel 发送携带频道名称的 HTTP 授权请求。安装广播时 Laravel 会尝试注册 /broadcasting/auth;如果未自动注册,可在 bootstrap/app.php 的路由配置中指向频道文件:
->withRouting(
web: __DIR__.'/../routes/web.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
php artisan channel:list 可列出注册的频道授权回调。本次未运行该命令。
频道支持隐式与显式模型绑定,但不支持 HTTP 路由那样的自动隐式绑定作用域限制。例如频道名同时含租户 ID 和订单 ID,并不意味着框架已经验证订单属于该租户。应在回调或政策中明确核对业务关系。
私有频道和 presence 频道默认使用应用的默认认证 guard。未认证的请求会被直接拒绝,授权回调不会执行。需要多个自定义 guard 时,可传入第三个参数:
Broadcast::channel('channel', function () {
// 返回基于实际业务关系的授权结果。
}, ['guards' => ['web', 'admin']]);
上例只是 guard 配置形状,不能把空回调直接当作可用授权规则。应只启用应用确实需要的认证路径。
频道多时,可用 php artisan make:channel OrderChannel 生成 App/Broadcasting/OrderChannel.php,再在路由中注册:
use App\Broadcasting\OrderChannel;
Broadcast::channel('orders.{order}', OrderChannel::class);
授权逻辑放在频道类的 join(User $user, Order $order): array|bool,例如返回 $user->id === $order->user_id。频道类由服务容器解析,可在构造器中类型提示所需依赖;模型绑定仍然可用。
避免发起请求的连接重复更新
考虑新增任务:HTTP 请求 /task 返回新任务 JSON,浏览器立即将它插入列表;服务器又广播同一任务的创建事件,监听器再次插入,于是列表出现两条。此时可排除发起请求的 socket:
broadcast(new OrderShipmentStatusUpdated($order))->toOthers();
事件必须使用 Illuminate\Broadcasting\InteractsWithSockets。Echo 初始化连接时得到 socket ID;使用全局 Axios 实例时,该 ID 会自动附在请求的 X-Socket-ID 头中,Laravel 读取它并要求广播服务排除相同 socket。若用自定义 HTTP 客户端,应自行将 Echo.socketId() 加到发往应用的相关请求头中。
需要精确理解:toOthers() 按 socket ID 排除连接,不是按用户账户排除其所有浏览器、所有标签页。它也不是可靠的业务去重机制或授权凭据;如果请求没有相应头,不能指望排除生效。
切换连接、匿名事件和容错
对特定事件选择其他广播连接,可写 broadcast(new OrderShipmentStatusUpdated($order))->via('pusher')。也可在事件构造器内调用 $this->broadcastVia('pusher'),但须使用 InteractsWithBroadcasting trait。广播连接与负责运行任务的队列连接是两件事。
不需要专用事件类时,Broadcast::on('channel')->send() 可以发送匿名事件,默认名称为 AnonymousEvent,默认数据为空;as() 设置名称,with() 设置数据。send() 入队,sendNow() 立即发送。private()、presence() 分别选择私有和 presence 频道,toOthers() 同样可用。
原文用公开的 Broadcast::on('orders.'.$order->id)->with($order) 展示 API。编辑调整:订单示例改为私有频道并选取字段,避免把整份订单公开广播:
Broadcast::private('orders.'.$order->id)
->as('OrderPlaced')
->with(['id' => $order->id, 'status' => $order->status])
->toOthers()
->send();
队列服务不可用或广播抛出异常时,可能影响用户请求。事件实现 Illuminate\Contracts\Broadcasting\ShouldRescue 后,Laravel 会通过 rescue helper 捕获广播尝试中的异常,向异常处理器报告,再继续流程。它适合把广播作为补充功能的场景;编辑补充:捕获并记录失败并不等于成功投递,也不应遮蔽对失败的监控。
监听、退出和框架 Hook
Echo 的 channel() 获取公开频道,private() 获取私有频道,随后通过 listen() 注册事件处理器。同一频道可串联多个 listen()。调用 stopListening('OrderShipmentStatusUpdated') 只停止特定事件的监听,不退出频道。
leaveChannel(name) 退出一个指定频道;leave(name) 还会退出与其对应的 private 与 presence 频道。页面卸载时清理订阅,能避免重复处理和不必要的连接活动。
Echo 默认假设事件位于 App\Events 命名空间,初始化时可用 namespace: 'App.Other.Namespace' 覆盖。监听名称前加 . 会禁用自动命名空间前缀,例如 .listen('.Namespace\\Event\\Class', callback)。
React、Vue、Svelte 的 useEcho 默认监听私有频道,并在消费它的组件卸载时自动离开。三个包中的接口同名,下面以 React 的 TypeScript 写法展示;Vue 在 setup 中导入 @laravel/echo-vue,Svelte 从 @laravel/echo-svelte 导入:
import { useEcho } from '@laravel/echo-react';
type OrderData = { order: { id: number; status: string } };
const { leaveChannel, leave, stopListening, listen } = useEcho<OrderData>(
`orders.${orderId}`,
['OrderShipmentStatusUpdated', 'OrderShipped'],
(event) => {
console.log(event.order.id, event.order.status);
},
);
第二个参数可以是单个事件名或多个事件名数组。类型参数提供编辑器检查,不会自动校验网络载荷。返回的 stopListening()、listen() 可以暂停或恢复监听;leaveChannel() 与 leave() 可手动结束订阅。
| 接口 | 用途 |
|---|---|
useEchoPublic('posts', 'PostPublished', callback) |
监听公开频道。 |
useEchoPresence('posts', 'PostPublished', callback) |
连接 presence 频道。 |
useConnectionStatus() |
返回随连接变化更新的状态。 |
useSocketId() |
返回当前 socket ID,重连获得新 ID 时更新。 |
状态值包括 connected(已连接)、connecting(初次连接中)、reconnecting(断线重连中)、disconnected(断开且未重连)、failed(连接失败并停止重试)。React 直接使用 Hook 返回的值;Vue 在模板中响应式展示;原文 Svelte 示例通过 status()、socketId() 读取。
Presence 频道:在授权基础上显示在线成员
Presence 频道可用于聊天室成员列表、协同查看等场景。它同样是私有频道,不过授权成功时应返回可公开给同频道成员的用户信息数组,而不是只返回 true;拒绝则返回 false 或 null。
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
return false;
});
canJoinRoom() 是原文假定由业务实现的方法。这里显式添加拒绝返回值,与原文隐式返回 null 的含义相同。不要把邮件地址、访问令牌等敏感字段加入 presence 用户数组。
Echo.join(`chat.${roomId}`)
.here((users) => { /* 初始化成员列表 */ })
.joining((user) => { /* 添加成员 */ })
.leaving((user) => { /* 移除成员 */ })
.error((error) => { /* 处理授权或响应解析错误 */ })
.listen('NewMessage', (event) => { /* 展示消息 */ });
here 在成功加入后立即运行,接收当前频道成员信息;joining 和 leaving 响应成员加入与离开;授权接口返回非 200 或 JSON 解析失败时会触发 error。服务端从 broadcastOn() 返回 new PresenceChannel('chat.'.$this->message->room_id) 即可向同一频道广播;普通 broadcast() 和 toOthers() 的规则仍适用。
加密私有频道
普通私有频道限制谁可以订阅,但广播服务处理的数据本身仍可读。当前文档说明 Pusher Channels 和 Mercure 可使用端到端加密私有频道,使应用及获得授权的客户端能够读取事件数据,而广播服务不能直接读取明文载荷。它与仅使用 TLS 的连接加密不是同一层保护。
配置前述驱动的加密密钥后,事件返回 Illuminate\Broadcasting\EncryptedPrivateChannel:
public function broadcastOn(): array
{
return [new EncryptedPrivateChannel('orders.'.$this->order->id)];
}
授权沿用普通私有频道的 orders.{orderId} 回调。前端使用 Echo.encryptedPrivate(`orders.${orderId}`) 订阅,再调用 listen()。Pusher 的默认 pusher-js 构建不含解密代码,需改用:
import Pusher from 'pusher-js/with-encryption';
window.Pusher = Pusher;
应同时核对服务器、Echo 与客户端 SDK 的实际版本和支持情况;本文没有把此能力推定为所有广播驱动都具备。
直接广播 Eloquent 模型变化
如果只是把模型创建、更新或删除反映到界面,逐个创建事件类可能重复。模型可以使用 Illuminate\Database\Eloquent\BroadcastsEvents trait,并实现 broadcastOn(string $event): array。原文以 Post 为例,user() 是 belongsTo(User::class),广播频道返回 [$this, $this->user]。
框架会在实例发生 created、updated、deleted、trashed、restored 事件时广播,并把相应操作字符串传给 broadcastOn()。需要抑制某种操作时,返回空数组:
public function broadcastOn(string $event): array
{
return match ($event) {
'deleted' => [],
default => [$this, $this->user],
};
}
模型直接作为返回值时,Laravel 按完整类名和主键构造私有频道,例如 ID 为 1 的 App\Models\User 对应 App.Models.User.1。也可显式返回 new PrivateChannel('user.'.$this->id);频道构造器还能接收模型,并按相同约定产生名称。需要查看名称时调用 $user->broadcastChannel()。
原文边界补充:若显式使用 new Channel($this->user),虽然名称仍遵从模型命名约定,频道却是公开的;构造器种类决定公开或私有,不能仅靠名称推断权限。
默认事件名是模型短类名加操作名:Post 更新产生 PostUpdated,User 删除产生 UserDeleted。默认载荷包含 model 及模型可广播属性,也可能包含 socket 信息。模型内可实现 broadcastAs(string $event): string|null 与 broadcastWith(string $event): array 分别自定义名称和内容;broadcastAs() 返回 null 时恢复默认命名。
public function broadcastAs(string $event): string|null
{
return $event === 'created' ? 'post.created' : null;
}
public function broadcastWith(string $event): array
{
return match ($event) {
'created' => ['title' => $this->title],
default => ['model' => $this],
};
}
这是原文展示接口的逻辑。默认分支仍发送完整模型;正式采用前应审查模型的可序列化字段,必要时改为逐字段白名单。
要控制底层事件创建,可覆写 newBroadcastableEvent(string $event),返回 Illuminate\Database\Eloquent\BroadcastableModelEventOccurred。例如在创建后调用 dontBroadcastToCurrentUser() 排除当前连接:
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
return (new BroadcastableModelEventOccurred($this, $event))
->dontBroadcastToCurrentUser();
}
该片段需导入上面的事件类。前端监听模型事件时加前导句点,因为它并不对应 App\Events 内的普通事件类:
Echo.private(`App.Models.User.${userId}`)
.listen('.UserUpdated', (event) => {
console.log(event.model);
});
三个前端集成都提供 useEchoModel,例如 useEchoModel('App.Models.User', userId, ['UserUpdated'], callback)。TypeScript 可用 useEchoModel<User, 'App.Models.User'>(...) 指定模型载荷类型,获得 event.model.id 等属性的编辑提示。类型声明应与实际广播白名单一致。
客户端事件与实时通知
打字提示等短暂消息可以由客户端直接发给其他连接,绕过 Laravel 请求处理。在 Pusher Channels 中,需先在应用后台 App Settings 启用 Client Events。Echo 的发送和接收接口是 whisper() 与 listenForWhisper():
Echo.private(`chat.${roomId}`)
.whisper('typing', { name: user.name });
Echo.private(`chat.${roomId}`)
.listenForWhisper('typing', (event) => {
console.log(event.name);
});
Hook 用户可从 useEcho(...) 返回值获取 channel,然后调用 channel().whisper(...) 和 channel().listenForWhisper(...)。静态审查补充:客户端事件由对端客户端提供,不能把其中的姓名、用户 ID 或业务状态当作已由服务器验证;它适合输入提示,不适合直接确认支付或修改权限。展示字符串时使用框架转义或文本节点,避免拼进 HTML。
Laravel 通知也可通过广播送达浏览器。先按 广播通知文档将通知配置为使用 broadcast channel,再按接收实体的类名与 ID 订阅:
const callback = (notification) => {
console.log(notification.type);
};
Echo.private(`App.Models.User.${userId}`).notification(callback);
// 不离开频道,只停止这个通知回调;必须传入同一函数对象。
Echo.private(`App.Models.User.${userId}`)
.stopListeningForNotification(callback);
默认频道文件含 App.Models.User.{id} 的授权回调。React、Vue、Svelte 可从 useEchoModel('App.Models.User', userId) 获取 channel(),再注册 notification()。
采用前的核对重点
一条完整的实时更新链路需要同时满足:事件在恰当时机派发,队列与广播服务可用,频道订阅通过认证及业务归属检查,载荷字段适合暴露,前端按正确名称监听并在生命周期结束时清理。事务提交与 X-Socket-ID 分别处理数据可见性和发起连接的重复更新,不能互相替代。
本次静态检查确认了原文示例中的公开频道、默认序列化、可配置明文 WebSocket、客户端事件信任边界,以及来源段落所示版本差异;未执行 PHP、JavaScript、Artisan、Composer、NPM 或 OpenSSL 示例,也未测试平台服务和实际授权配置。静态审查没有发现某类问题,不代表应用不存在漏洞。
来源与归属:Laravel 文档贡献者,原始入口;采用 13.x 版本文档,并参考 官方部署要求确认 PHP 8.3+。原始文档与代码的权利归原作者及项目权利人;不把框架许可证自动推定为所有站点内容的许可证。本文配图为原创流程示意图。












暂无评论内容