广播
简介
在许多现代 Web 应用程序中,WebSocket 用于实现实时、动态更新的用户界面。当服务器上的某些数据更新时,通常会通过 WebSocket 连接发送一条消息,由客户端处理。WebSocket 提供了一种更高效的替代方案,无需持续轮询应用程序的服务器以获取应在 UI 中反映的数据更改。
例如,假设你的应用程序能够将用户的数据导出为 CSV 文件并通过电子邮件发送给他们。但是,创建此 CSV 文件需要几分钟时间,因此你选择在队列任务中创建和邮寄 CSV。当 CSV 已创建并邮寄给用户时,我们可以使用事件广播来分发一个 App\Events\UserDataExported 事件,该事件由我们应用程序的 JavaScript 接收。一旦接收到事件,我们就可以向用户显示一条消息,告知他们的 CSV 已通过电子邮件发送给他们,而无需他们刷新页面。
为了帮助你构建此类功能,Laravel 可以轻松地通过 WebSocket 连接“广播”你的服务器端 Laravel 事件。广播你的 Laravel 事件允许你在服务器端 Laravel 应用程序和客户端 JavaScript 应用程序之间共享相同的事件名称和数据。
广播背后的核心概念很简单:客户端在前端连接到命名频道,而你的 Laravel 应用程序在后端将事件广播到这些频道。这些事件可以包含你希望提供给前端的任何附加数据。
支持的驱动程序
默认情况下,Laravel 包含三个服务器端广播驱动程序供你选择:Laravel Reverb、Pusher Channels 和 Ably。
NOTE
在深入研究事件广播之前,请确保你已经阅读了 Laravel 关于事件和监听器的文档。
快速入门
默认情况下,新 Laravel 应用程序中未启用广播。你可以使用 install:broadcasting Artisan 命令启用广播:
php artisan install:broadcastinginstall:broadcasting 命令将提示你选择要使用的事件广播服务。此外,它还将创建 config/broadcasting.php 配置文件和 routes/channels.php 文件,你可以在其中注册应用程序的广播授权路由和回调。
Laravel 开箱即支持多个广播驱动程序:Laravel Reverb、Pusher Channels、Ably 以及用于本地开发和调试的 log 驱动程序。此外,还包含一个 null 驱动程序,允许你在测试期间禁用广播。config/broadcasting.php 配置文件中包含了每个驱动程序的配置示例。
应用程序的所有事件广播配置都存储在 config/broadcasting.php 配置文件中。如果此文件在你的应用程序中不存在,请不要担心;运行 install:broadcasting Artisan 命令时会创建它。
后续步骤
一旦启用了事件广播,你就可以进一步了解定义广播事件和监听事件。如果你使用的是 Laravel 的 React 或 Vue 启动工具包,则可以使用 Echo 的 useEcho 钩子监听事件。
NOTE
在广播任何事件之前,你应该首先配置并运行一个队列工作者。所有事件广播都通过队列任务完成,这样应用程序的响应时间就不会受到广播事件的严重影响。
服务器端安装
要开始使用 Laravel 的事件广播,我们需要在 Laravel 应用程序中进行一些配置,并安装几个包。
事件广播由服务器端广播驱动程序完成,该驱动程序广播你的 Laravel 事件,以便 Laravel Echo(一个 JavaScript 库)可以在浏览器客户端中接收它们。别担心——我们将逐步介绍安装过程的每个部分。
Reverb
要快速启用 Laravel 的广播功能并将 Reverb 用作事件广播器,请使用 --reverb 选项调用 install:broadcasting Artisan 命令。此 Artisan 命令将安装 Reverb 所需的 Composer 和 NPM 包,并使用适当的变量更新你的应用程序的 .env 文件:
php artisan install:broadcasting --reverb手动安装
运行 install:broadcasting 命令时,系统将提示你安装 Laravel Reverb。当然,你也可以使用 Composer 包管理器手动安装 Reverb:
composer require laravel/reverb安装包后,你可以运行 Reverb 的安装命令来发布配置、添加 Reverb 所需的环境变量,并在应用程序中启用事件广播:
php artisan reverb:install你可以在 Reverb 文档中找到详细的 Reverb 安装和使用说明。
Pusher Channels
要快速启用 Laravel 的广播功能并将 Pusher 用作事件广播器,请使用 --pusher 选项调用 install:broadcasting Artisan 命令。此 Artisan 命令将提示你输入 Pusher 凭据,安装 Pusher PHP 和 JavaScript SDK,并使用适当的变量更新你的应用程序的 .env 文件:
php artisan install:broadcasting --pusher手动安装
要手动安装 Pusher 支持,你应该使用 Composer 包管理器安装 Pusher Channels PHP SDK:
composer require pusher/pusher-php-server接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Pusher Channels 凭据。此文件中已包含一个 Pusher Channels 配置示例,允许你快速指定你的密钥、密钥和应用程序 ID。通常,你应该在应用程序的 .env 文件中配置 Pusher Channels 凭据:
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"config/broadcasting.php 文件中的 pusher 配置还允许你指定 Channels 支持的其他 options,例如集群。
然后,在你的应用程序的 .env 文件中将 BROADCAST_CONNECTION 环境变量设置为 pusher:
BROADCAST_CONNECTION=pusher最后,你可以准备安装和配置 Laravel Echo,它将在客户端接收广播事件。
Ably
NOTE
以下文档讨论了如何在“Pusher 兼容性”模式下使用 Ably。但是,Ably 团队推荐并维护了一个能够利用 Ably 提供的独特功能的广播器和 Echo 客户端。有关使用 Ably 维护的驱动程序的更多信息,请查阅 Ably 的 Laravel 广播器文档。
要快速启用 Laravel 的广播功能并将 Ably 用作事件广播器,请使用 --ably 选项调用 install:broadcasting Artisan 命令。此 Artisan 命令将提示你输入 Ably 凭据,安装 Ably PHP 和 JavaScript SDK,并使用适当的变量更新你的应用程序的 .env 文件:
php artisan install:broadcasting --ably在继续之前,你应该在 Ably 应用程序设置中启用 Pusher 协议支持。你可以在 Ably 应用程序设置仪表板的“协议适配器设置”部分中启用此功能。
手动安装
要手动安装 Ably 支持,你应该使用 Composer 包管理器安装 Ably PHP SDK:
composer require ably/ably-php接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Ably 凭据。此文件中已包含一个 Ably 配置示例,允许你快速指定你的密钥。通常,此值应通过 ABLY_KEY 环境变量设置:
ABLY_KEY=your-ably-key然后,在你的应用程序的 .env 文件中将 BROADCAST_CONNECTION 环境变量设置为 ably:
BROADCAST_CONNECTION=ably最后,你可以准备安装和配置 Laravel Echo,它将在客户端接收广播事件。
客户端安装
Reverb
Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听由服务器端广播驱动程序广播的事件变得轻而易举。
当通过 install:broadcasting Artisan 命令安装 Laravel Reverb 时,Reverb 和 Echo 的脚手架和配置将自动注入到你的应用程序中。但是,如果你希望手动配置 Laravel Echo,可以按照下面的说明进行操作。
手动安装
要手动为你的应用程序前端配置 Laravel Echo,首先安装 pusher-js 包,因为 Reverb 利用 Pusher 协议进行 WebSocket 订阅、频道和消息:
npm install --save-dev laravel-echo pusher-js安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例。一个很好的地方是在 Laravel 框架附带的 resources/js/bootstrap.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'],
});import { configureEcho } from "@laravel/echo-react";
configureEcho({
broadcaster: "reverb",
// key: import.meta.env.VITE_REVERB_APP_KEY,
// wsHost: import.meta.env.VITE_REVERB_HOST,
// wsPort: import.meta.env.VITE_REVERB_PORT,
// wssPort: import.meta.env.VITE_REVERB_PORT,
// forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
// enabledTransports: ['ws', 'wss'],
});import { configureEcho } from "@laravel/echo-vue";
configureEcho({
broadcaster: "reverb",
// key: import.meta.env.VITE_REVERB_APP_KEY,
// wsHost: import.meta.env.VITE_REVERB_HOST,
// wsPort: import.meta.env.VITE_REVERB_PORT,
// wssPort: import.meta.env.VITE_REVERB_PORT,
// forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
// enabledTransports: ['ws', 'wss'],
});接下来,你应该编译应用程序的资源:
npm run buildWARNING
Laravel Echo reverb 广播器需要 laravel-echo v1.16.0 或更高版本。
Pusher Channels
Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听由服务器端广播驱动程序广播的事件变得轻而易举。
当通过 install:broadcasting --pusher Artisan 命令安装广播支持时,Pusher 和 Echo 的脚手架和配置将自动注入到你的应用程序中。但是,如果你希望手动配置 Laravel Echo,可以按照下面的说明进行操作。
手动安装
要手动为你的应用程序前端配置 Laravel Echo,首先安装 laravel-echo 和 pusher-js 包,它们利用 Pusher 协议进行 WebSocket 订阅、频道和消息:
npm install --save-dev laravel-echo pusher-js安装 Echo 后,你就可以在应用程序的 resources/js/bootstrap.js 文件中创建一个新的 Echo 实例:
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
});import { configureEcho } from "@laravel/echo-react";
configureEcho({
broadcaster: "pusher",
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true,
// wsHost: import.meta.env.VITE_PUSHER_HOST,
// wsPort: import.meta.env.VITE_PUSHER_PORT,
// wssPort: import.meta.env.VITE_PUSHER_PORT,
// enabledTransports: ["ws", "wss"],
});import { configureEcho } from "@laravel/echo-vue";
configureEcho({
broadcaster: "pusher",
// key: import.meta.env.VITE_PUSHER_APP_KEY,
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
// forceTLS: true,
// wsHost: import.meta.env.VITE_PUSHER_HOST,
// wsPort: import.meta.env.VITE_PUSHER_PORT,
// wssPort: import.meta.env.VITE_PUSHER_PORT,
// enabledTransports: ["ws", "wss"],
});接下来,你应该在应用程序的 .env 文件中为 Pusher 环境变量定义适当的值。如果这些变量在你的 .env 文件中尚不存在,你应该添加它们:
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"
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}"根据你的应用程序需要调整 Echo 配置后,你可以编译应用程序的资源:
npm run buildNOTE
要了解有关编译 JavaScript 应用程序资源的更多信息,请查阅 Vite 文档。
使用现有客户端实例
如果你已经有一个预配置的 Pusher Channels 客户端实例,并希望 Echo 使用它,你可以通过 client 配置选项将其传递给 Echo:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
const options = {
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY
}
window.Echo = new Echo({
...options,
client: new Pusher(options.key, options)
});Ably
NOTE
以下文档讨论了如何在“Pusher 兼容性”模式下使用 Ably。但是,Ably 团队推荐并维护了一个能够利用 Ably 提供的独特功能的广播器和 Echo 客户端。有关使用 Ably 维护的驱动程序的更多信息,请查阅 Ably 的 Laravel 广播器文档。
Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听由服务器端广播驱动程序广播的事件变得轻而易举。
当通过 install:broadcasting --ably Artisan 命令安装广播支持时,Ably 和 Echo 的脚手架和配置将自动注入到你的应用程序中。但是,如果你希望手动配置 Laravel Echo,可以按照下面的说明进行操作。
手动安装
要手动为你的应用程序前端配置 Laravel Echo,首先安装 laravel-echo 和 pusher-js 包,它们利用 Pusher 协议进行 WebSocket 订阅、频道和消息:
npm install --save-dev laravel-echo pusher-js在继续之前,你应该在 Ably 应用程序设置中启用 Pusher 协议支持。你可以在 Ably 应用程序设置仪表板的“协议适配器设置”部分中启用此功能。
安装 Echo 后,你就可以在应用程序的 resources/js/bootstrap.js 文件中创建一个新的 Echo 实例:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
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,
});import { configureEcho } from "@laravel/echo-react";
configureEcho({
broadcaster: "ably",
// key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
// wsHost: "realtime-pusher.ably.io",
// wsPort: 443,
// disableStats: true,
// encrypted: true,
});import { configureEcho } from "@laravel/echo-vue";
configureEcho({
broadcaster: "ably",
// key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
// wsHost: "realtime-pusher.ably.io",
// wsPort: 443,
// disableStats: true,
// encrypted: true,
});你可能已经注意到,我们的 Ably Echo 配置引用了一个 VITE_ABLY_PUBLIC_KEY 环境变量。此变量的值应该是你的 Ably 公钥。你的公钥是你的 Ably 密钥中 : 字符之前的部分。
根据你的需要调整 Echo 配置后,你可以编译应用程序的资源:
npm run devNOTE
要了解有关编译 JavaScript 应用程序资源的更多信息,请查阅 Vite 文档。
概念概述
Laravel 的事件广播允许你使用基于驱动程序的 WebSocket 方法将服务器端的 Laravel 事件广播到客户端的 JavaScript 应用程序。目前,Laravel 附带 Laravel Reverb、Pusher Channels 和 Ably 驱动程序。事件可以在客户端使用 Laravel Echo JavaScript 包轻松消费。
事件通过“频道”广播,这些频道可以指定为公共或私有。任何访问你应用程序的访客都可以订阅公共频道,无需任何身份验证或授权;但是,为了订阅私有频道,用户必须经过身份验证并授权监听该频道。
使用示例应用程序
在深入研究事件广播的每个组件之前,让我们以一个电子商务商店为例进行高层概述。
在我们的应用程序中,假设我们有一个页面,允许用户查看其订单的发货状态。我们还假设当应用程序处理发货状态更新时,会触发一个 OrderShipmentStatusUpdated 事件:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);ShouldBroadcast 接口
当用户查看其中一个订单时,我们不希望他们必须刷新页面才能查看状态更新。相反,我们希望在他们创建更新时将更新广播到应用程序。因此,我们需要用 ShouldBroadcast 接口标记 OrderShipmentStatusUpdated 事件。这将指示 Laravel 在事件触发时广播它:
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
/**
* 订单实例。
*
* @var \App\Models\Order
*/
public $order;
}ShouldBroadcast 接口要求我们的事件定义一个 broadcastOn 方法。此方法负责返回事件应广播到的频道。生成的事件类上已经定义了此方法的一个空 stub,所以我们只需要填写其详细信息。我们只希望订单的创建者能够查看状态更新,因此我们将在一个绑定到订单的私有频道上广播该事件:
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
/**
* 获取事件应广播到的频道。
*/
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.'.$this->order->id);
}如果你希望事件在多个频道上广播,可以返回一个 array:
use Illuminate\Broadcasting\PrivateChannel;
/**
* 获取事件应广播到的频道。
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.'.$this->order->id),
// ...
];
}授权频道
请记住,用户必须获得授权才能监听私有频道。我们可以在应用程序的 routes/channels.php 文件中定义频道授权规则。在此示例中,我们需要验证任何试图监听私有 orders.1 频道的用户确实是该订单的创建者:
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 方法接受两个参数:频道名称和一个回调函数,该函数返回 true 或 false,指示用户是否有权监听该频道。
所有授权回调都接收当前通过身份验证的用户作为第一个参数,以及任何额外的通配符参数作为后续参数。在此示例中,我们使用 {orderId} 占位符来指示频道名称的“ID”部分是一个通配符。
监听事件广播
接下来,剩下的就是在我们的 JavaScript 应用程序中监听事件。我们可以使用 Laravel Echo 来做到这一点。Laravel Echo 内置的 React 和 Vue 钩子使其易于上手,并且默认情况下,事件的所有公共属性都将包含在广播事件中:
import { useEcho } from "@laravel/echo-react";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>定义广播事件
要告知 Laravel 应广播给定事件,你必须在事件类上实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast 接口。此接口已导入到框架生成的所有事件类中,因此你可以轻松地将其添加到你的任何事件中。
ShouldBroadcast 接口要求你实现一个方法:broadcastOn。broadcastOn 方法应返回事件应广播到的频道或频道数组。频道应为 Channel、PrivateChannel 或 PresenceChannel 的实例。Channel 实例表示任何用户都可以订阅的公共频道,而 PrivateChannel 和 PresenceChannel 表示需要频道授权的私有频道:
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast
{
use SerializesModels;
/**
* 创建一个新的事件实例。
*/
public function __construct(
public User $user,
) {}
/**
* 获取事件应广播到的频道。
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('user.'.$this->user->id),
];
}
}实现 ShouldBroadcast 接口后,你只需要像往常一样触发事件。一旦事件被触发,一个队列任务将使用你指定的广播驱动程序自动广播该事件。
广播名称
默认情况下,Laravel 将使用事件的类名进行广播。但是,你可以通过在事件上定义一个 broadcastAs 方法来自定义广播名称:
/**
* 事件的广播名称。
*/
public function broadcastAs(): string
{
return 'server.created';
}如果你使用 broadcastAs 方法自定义了广播名称,则应确保使用前导 . 字符注册监听器。这将指示 Echo 不要将应用程序的命名空间添加到事件前:
.listen('.server.created', function (e) {
// ...
});广播数据
当事件被广播时,其所有 public 属性都会被自动序列化并作为事件的负载进行广播,允许你从 JavaScript 应用程序访问其任何公共数据。因此,例如,如果你的事件有一个包含 Eloquent 模型的公共 $user 属性,则事件的广播负载将是:
{
"user": {
"id": 1,
"name": "Patrick Stewart"
...
}
}但是,如果你希望对广播负载进行更细粒度的控制,可以向事件添加一个 broadcastWith 方法。此方法应返回你希望作为事件负载广播的数据数组:
/**
* 获取要广播的数据。
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return ['id' => $this->user->id];
}广播队列
默认情况下,每个广播事件都放置在 queue.php 配置文件中指定的默认队列连接的默认队列上。你可以通过使用事件类上的 Connection 和 Queue 属性来自定义广播器使用的队列连接和名称:
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;
#[Connection('redis')]
#[Queue('default')]
class ServerCreated implements ShouldBroadcast
{
// ...
}或者,你可以通过在事件上定义一个 broadcastQueue 方法来自定义队列名称:
/**
* 放置广播任务的队列名称。
*/
public function broadcastQueue(): string
{
return 'default';
}如果你希望使用 sync 队列而不是默认队列驱动程序来广播事件,可以实现 ShouldBroadcastNow 接口而不是 ShouldBroadcast:
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
// ...
}广播条件
有时你希望仅在给定条件为真时才广播事件。你可以通过向事件类添加一个 broadcastWhen 方法来定义这些条件:
/**
* 确定此事件是否应广播。
*/
public function broadcastWhen(): bool
{
return $this->order->value > 100;
}广播与数据库事务
当广播事件在数据库事务中分发时,它们可能会在数据库事务提交之前被队列处理。发生这种情况时,你在数据库事务期间对模型或数据库记录所做的任何更新可能尚未反映在数据库中。此外,在事务中创建的任何模型或数据库记录可能不存在于数据库中。如果你的事件依赖于这些模型,则在处理广播事件的作业时可能会发生意外错误。
如果你的队列连接的 after_commit 配置选项设置为 false,你仍然可以通过在事件类上实现 ShouldDispatchAfterCommit 接口来指示应在所有打开的数据库事务提交后分发特定的广播事件:
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
use SerializesModels;
}NOTE
要了解有关解决这些问题的更多信息,请查阅关于队列任务和数据库事务的文档。
授权频道
私有频道要求你授权当前通过身份验证的用户确实可以监听该频道。这是通过向你的 Laravel 应用程序发出带有频道名称的 HTTP 请求,并允许你的应用程序确定用户是否可以监听该频道来完成的。当使用 Laravel Echo 时,用于授权订阅私有频道的 HTTP 请求将自动进行。
安装广播后,Laravel 会尝试自动注册 /broadcasting/auth 路由来处理授权请求。如果 Laravel 无法自动注册这些路由,你可以在应用程序的 /bootstrap/app.php 文件中手动注册它们:
->withRouting(
web: __DIR__.'/../routes/web.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)定义授权回调
接下来,我们需要定义逻辑,该逻辑将实际确定当前通过身份验证的用户是否可以监听给定频道。这是在由 install:broadcasting Artisan 命令创建的 routes/channels.php 文件中完成的。在此文件中,你可以使用 Broadcast::channel 方法注册频道授权回调:
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 方法接受两个参数:频道名称和一个回调函数,该函数返回 true 或 false,指示用户是否有权监听该频道。
所有授权回调都接收当前通过身份验证的用户作为第一个参数,以及任何额外的通配符参数作为后续参数。在此示例中,我们使用 {orderId} 占位符来指示频道名称的“ID”部分是一个通配符。
你可以使用 channel:list Artisan 命令查看应用程序的广播授权回调列表:
php artisan channel:list授权回调模型绑定
就像 HTTP 路由一样,频道路由也可以利用隐式和显式路由模型绑定。例如,你可以请求一个实际的 Order 模型实例,而不是接收字符串或数字订单 ID:
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
return $user->id === $order->user_id;
});WARNING
与 HTTP 路由模型绑定不同,频道模型绑定不支持自动隐式模型绑定作用域。但是,这通常不是问题,因为大多数频道可以基于单个模型的唯一主键进行作用域限定。
授权回调身份验证
私有和出席广播频道通过你应用程序的默认身份验证看守器对当前用户进行身份验证。如果用户未通过身份验证,频道授权将自动被拒绝,并且授权回调永远不会执行。但是,如果需要,你可以分配多个自定义看守器来对传入请求进行身份验证:
Broadcast::channel('channel', function () {
// ...
}, ['guards' => ['web', 'admin']]);定义频道类
如果你的应用程序消费了许多不同的频道,你的 routes/channels.php 文件可能会变得庞大。因此,你可以使用频道类而不是使用闭包来授权频道。要生成一个频道类,请使用 make:channel Artisan 命令。此命令将把一个新的频道类放在 App/Broadcasting 目录中。
php artisan make:channel OrderChannel接下来,在你的 routes/channels.php 文件中注册你的频道:
use App\Broadcasting\OrderChannel;
Broadcast::channel('orders.{order}', OrderChannel::class);最后,你可以将频道的授权逻辑放在频道类的 join 方法中。此 join 方法将包含你通常放在频道授权闭包中的相同逻辑。你还可以利用频道模型绑定:
<?php
namespace App\Broadcasting;
use App\Models\Order;
use App\Models\User;
class OrderChannel
{
/**
* 创建一个新的频道实例。
*/
public function __construct() {}
/**
* 验证用户对频道的访问权限。
*/
public function join(User $user, Order $order): array|bool
{
return $user->id === $order->user_id;
}
}NOTE
与 Laravel 中的许多其他类一样,频道类将由服务容器自动解析。因此,你可以在其构造函数中类型提示你的频道所需的任何依赖项。
广播事件
一旦你定义了一个事件并用 ShouldBroadcast 接口标记了它,你只需要使用事件的 dispatch 方法触发事件。事件分发器将注意到该事件已用 ShouldBroadcast 接口标记,并将该事件排队以进行广播:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);仅发送给其他人
在构建使用事件广播的应用程序时,你可能偶尔需要将事件广播到给定频道的所有订阅者,但不包括当前用户。你可以使用 broadcast 辅助函数和 toOthers 方法来实现这一点:
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->toOthers();为了更好地理解何时可能想要使用 toOthers 方法,让我们设想一个任务列表应用程序,用户可以通过输入任务名称来创建新任务。为了创建任务,你的应用程序可能会向 /task URL 发出一个请求,该请求广播任务的创建并返回新任务的 JSON 表示。当你的 JavaScript 应用程序收到来自端点的响应时,它可能会直接将新任务插入到其任务列表中,如下所示:
axios.post('/task', task)
.then((response) => {
this.tasks.push(response.data);
});但是,请记住,我们也广播了任务的创建。如果你的 JavaScript 应用程序也在监听此事件以将任务添加到任务列表,那么你的列表中会出现重复的任务:一个来自端点,一个来自广播。你可以通过使用 toOthers 方法来解决这个问题,该方法指示广播器不要将事件广播给当前用户。
WARNING
你的事件必须使用 Illuminate\Broadcasting\InteractsWithSockets trait 才能调用 toOthers 方法。
配置
当你初始化一个 Laravel Echo 实例时,会为该连接分配一个套接字 ID。如果你正在使用全局的 Axios 实例从你的 JavaScript 应用程序发出 HTTP 请求,则该套接字 ID 将自动作为 X-Socket-ID 标头附加到每个传出请求。然后,当你调用 toOthers 方法时,Laravel 将从标头中提取套接字 ID,并指示广播器不要广播给任何具有该套接字 ID 的连接。
如果你没有使用全局的 Axios 实例,你将需要手动配置你的 JavaScript 应用程序,以使用所有传出请求发送 X-Socket-ID 标头。你可以使用 Echo.socketId 方法检索套接字 ID:
var socketId = Echo.socketId();自定义连接
如果你的应用程序与多个广播连接交互,并且你想要使用默认广播器以外的广播器广播事件,你可以使用 via 方法指定要将事件推送到哪个连接:
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');或者,你可以通过调用事件构造函数中的 broadcastVia 方法来指定事件的广播连接。但是,在执行此操作之前,你应确保事件类使用了 InteractsWithBroadcasting trait:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithBroadcasting;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
use InteractsWithBroadcasting;
/**
* 创建一个新的事件实例。
*/
public function __construct()
{
$this->broadcastVia('pusher');
}
}匿名事件
有时,你可能希望向应用程序的前端广播一个简单的事件,而无需创建一个专门的事件类。为了方便起见,Broadcast 门面允许你广播“匿名事件”:
Broadcast::on('orders.'.$order->id)->send();上面的示例将广播以下事件:
{
"event": "AnonymousEvent",
"data": "[]",
"channel": "orders.1"
}使用 as 和 with 方法,你可以自定义事件的名称和数据:
Broadcast::on('orders.'.$order->id)
->as('OrderPlaced')
->with($order)
->send();上面的示例将广播类似于以下的事件:
{
"event": "OrderPlaced",
"data": "{ id: 1, total: 100 }",
"channel": "orders.1"
}如果你希望将匿名事件广播到私有或出席频道,可以使用 private 和 presence 方法:
Broadcast::private('orders.'.$order->id)->send();
Broadcast::presence('channels.'.$channel->id)->send();使用 send 方法广播匿名事件会将事件分发到你的应用程序的队列进行处理。但是,如果你希望立即广播该事件,可以使用 sendNow 方法:
Broadcast::on('orders.'.$order->id)->sendNow();要将事件广播给除当前通过身份验证的用户之外的所有频道订阅者,可以调用 toOthers 方法:
Broadcast::on('orders.'.$order->id)
->toOthers()
->send();挽救广播
当你的应用程序的队列服务器不可用或 Laravel 在广播事件时遇到错误时,会抛出一个异常,这通常会导致最终用户看到应用程序错误。由于事件广播通常是对应用程序核心功能的补充,你可以通过在你的事件上实现 ShouldRescue 接口来防止这些异常干扰用户体验。
实现 ShouldRescue 接口的事件在广播尝试期间会自动利用 Laravel 的 rescue 辅助函数。此辅助函数会捕获任何异常,将它们报告给你的应用程序的异常处理程序以进行日志记录,并允许应用程序继续正常执行,而不会中断用户的工作流程:
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldRescue;
class ServerCreated implements ShouldBroadcast, ShouldRescue
{
// ...
}接收广播
监听事件
一旦你安装并实例化了 Laravel Echo,你就可以开始监听从你的 Laravel 应用程序广播的事件了。首先,使用 channel 方法获取一个频道实例,然后调用 listen 方法来监听指定事件:
Echo.channel(`orders.${this.order.id}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order.name);
});如果你希望监听私有频道上的事件,请改用 private 方法。你可以继续链式调用 listen 方法来监听单个频道上的多个事件:
Echo.private(`orders.${this.order.id}`)
.listen(/* ... */)
.listen(/* ... */)
.listen(/* ... */);停止监听事件
如果你希望停止监听给定事件而不离开频道,可以使用 stopListening 方法:
Echo.private(`orders.${this.order.id}`)
.stopListening('OrderShipmentStatusUpdated');离开频道
要离开一个频道,你可以在 Echo 实例上调用 leaveChannel 方法:
Echo.leaveChannel(`orders.${this.order.id}`);如果你希望离开一个频道及其相关的私有和出席频道,可以调用 leave 方法:
Echo.leave(`orders.${this.order.id}`);命名空间
你可能已经注意到,在上面的示例中,我们没有为事件类指定完整的 App\Events 命名空间。这是因为 Echo 会自动假定事件位于 App\Events 命名空间中。但是,你可以在实例化 Echo 时通过传递 namespace 配置选项来配置根命名空间:
window.Echo = new Echo({
broadcaster: 'pusher',
// ...
namespace: 'App.Other.Namespace'
});或者,当你使用 Echo 订阅事件时,可以在事件类前加上 .。这将允许你始终指定完全限定的类名:
Echo.channel('orders')
.listen('.Namespace\\Event\\Class', (e) => {
// ...
});使用 React 或 Vue
Laravel Echo 包含 React 和 Vue 钩子,使监听事件变得轻而易举。首先,调用 useEcho 钩子,它用于监听私有事件。当消费组件被卸载时,useEcho 钩子将自动离开频道:
import { useEcho } from "@laravel/echo-react";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
</script>你可以通过向 useEcho 提供一个事件数组来监听多个事件:
useEcho(
`orders.${orderId}`,
["OrderShipmentStatusUpdated", "OrderShipped"],
(e) => {
console.log(e.order);
},
);你还可以指定广播事件负载数据的类型,提供更大的类型安全性和编辑便利性:
type OrderData = {
order: {
id: number;
user: {
id: number;
name: string;
};
created_at: string;
};
};
useEcho<OrderData>(`orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => {
console.log(e.order.id);
console.log(e.order.user.id);
});当消费组件被卸载时,useEcho 钩子将自动离开频道;但是,你可以在必要时利用返回的函数以编程方式手动停止/开始监听频道:
import { useEcho } from "@laravel/echo-react";
const { leaveChannel, leave, stopListening, listen } = useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// 停止监听而不离开频道...
stopListening();
// 再次开始监听...
listen();
// 离开频道...
leaveChannel();
// 离开频道及其相关的私有和出席频道...
leave();<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { leaveChannel, leave, stopListening, listen } = useEcho(
`orders.${orderId}`,
"OrderShipmentStatusUpdated",
(e) => {
console.log(e.order);
},
);
// 停止监听而不离开频道...
stopListening();
// 再次开始监听...
listen();
// 离开频道...
leaveChannel();
// 离开频道及其相关的私有和出席频道...
leave();
</script>连接到公共频道
要连接到公共频道,你可以使用 useEchoPublic 钩子:
import { useEchoPublic } from "@laravel/echo-react";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});<script setup lang="ts">
import { useEchoPublic } from "@laravel/echo-vue";
useEchoPublic("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>连接到出席频道
要连接到出席频道,你可以使用 useEchoPresence 钩子:
import { useEchoPresence } from "@laravel/echo-react";
useEchoPresence("posts", "PostPublished", (e) => {
console.log(e.post);
});<script setup lang="ts">
import { useEchoPresence } from "@laravel/echo-vue";
useEchoPresence("posts", "PostPublished", (e) => {
console.log(e.post);
});
</script>连接状态
你可以使用 useConnectionStatus 钩子检索当前的 WebSocket 连接状态,该钩子提供响应式状态,当连接状态更改时自动更新:
import { useConnectionStatus } from "@laravel/echo-react";
function ConnectionIndicator() {
const status = useConnectionStatus();
return <div>Connection: {status}</div>;
}<script setup lang="ts">
import { useConnectionStatus } from "@laravel/echo-vue";
const status = useConnectionStatus();
</script>
<template>
<div>Connection: {{ status }}</div>
</template>可能的状态值为:
connected- 已成功连接到 WebSocket 服务器。connecting- 正在进行初始连接尝试。reconnecting- 在断开连接后尝试重新连接。disconnected- 未连接且不尝试重新连接。failed- 连接失败且不会重试。
出席频道
出席频道在私有频道安全性的基础上构建,同时增加了了解谁订阅了该频道的额外功能。这使得构建强大的协作应用程序功能变得容易,例如在另一个用户查看同一页面时通知用户,或列出聊天室的成员。
授权出席频道
所有出席频道也是私有频道;因此,用户必须获得授权才能访问它们。但是,在为出席频道定义授权回调时,如果用户有权加入频道,你不会返回 true。相反,你应该返回一个关于用户的数据数组。
授权回调返回的数据将提供给你的 JavaScript 应用程序中的出席频道事件监听器。如果用户无权加入出席频道,你应该返回 false 或 null:
use App\Models\User;
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});加入出席频道
要加入出席频道,你可以使用 Echo 的 join 方法。join 方法将返回一个 PresenceChannel 实现,除了公开 listen 方法外,它还允许你订阅 here、joining 和 leaving 事件。
Echo.join(`chat.${roomId}`)
.here((users) => {
// ...
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
})
.error((error) => {
console.error(error);
});here 回调将在频道成功加入后立即执行,并将接收一个包含当前订阅该频道的所有其他用户的用户信息的数组。joining 方法将在新用户加入频道时执行,而 leaving 方法将在用户离开频道时执行。error 方法将在身份验证端点返回 200 以外的 HTTP 状态码或解析返回的 JSON 时出现问题时执行。
广播到出席频道
出席频道可以像公共或私有频道一样接收事件。使用聊天室的例子,我们可能希望将 NewMessage 事件广播到房间的出席频道。为此,我们将从事件的 broadcastOn 方法返回一个 PresenceChannel 实例:
/**
* 获取事件应广播到的频道。
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PresenceChannel('chat.'.$this->message->room_id),
];
}与其他事件一样,你可以使用 broadcast 辅助函数和 toOthers 方法来排除当前用户接收广播:
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();与其他类型的事件一样,你可以使用 Echo 的 listen 方法监听发送到出席频道的事件:
Echo.join(`chat.${roomId}`)
.here(/* ... */)
.joining(/* ... */)
.leaving(/* ... */)
.listen('NewMessage', (e) => {
// ...
});模型广播
WARNING
在阅读以下关于模型广播的文档之前,我们建议你熟悉 Laravel 模型广播服务的一般概念,以及如何手动创建和监听广播事件。
当你的应用程序的 Eloquent 模型被创建、更新或删除时,广播事件是很常见的。当然,这可以通过手动为 Eloquent 模型状态更改定义自定义事件并用 ShouldBroadcast 接口标记这些事件来轻松实现。
但是,如果你在应用程序中未将这些事件用于任何其他目的,那么为广播它们而创建事件类可能会很麻烦。为了解决这个问题,Laravel 允许你指示一个 Eloquent 模型应自动广播其状态更改。
首先,你的 Eloquent 模型应使用 Illuminate\Database\Eloquent\BroadcastsEvents trait。此外,模型应定义一个 broadcastOn 方法,该方法将返回一个频道数组,模型的这些事件应广播到这些频道上:
<?php
namespace App\Models;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
use BroadcastsEvents, HasFactory;
/**
* 获取帖子所属的用户。
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* 获取模型事件应广播到的频道。
*
* @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
*/
public function broadcastOn(string $event): array
{
return [$this, $this->user];
}
}一旦你的模型包含此 trait 并定义了其广播频道,它将在模型实例被创建、更新、删除、软删除或恢复时自动开始广播事件。
此外,你可能已经注意到 broadcastOn 方法接收一个字符串 $event 参数。此参数包含模型上发生的事件类型,其值将为 created、updated、deleted、trashed 或 restored。通过检查此变量的值,你可以确定为特定事件模型应广播到哪些频道(如果有):
/**
* 获取模型事件应广播到的频道。
*
* @return array<string, array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>>
*/
public function broadcastOn(string $event): array
{
return match ($event) {
'deleted' => [],
default => [$this, $this->user],
};
}自定义模型广播事件创建
有时,你可能希望自定义 Laravel 如何创建底层的模型广播事件。你可以通过在 Eloquent 模型上定义一个 newBroadcastableEvent 方法来实现。此方法应返回一个 Illuminate\Database\Eloquent\BroadcastableModelEventOccurred 实例:
use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;
/**
* 为模型创建一个新的可广播模型事件。
*/
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
return (new BroadcastableModelEventOccurred(
$this, $event
))->dontBroadcastToCurrentUser();
}模型广播约定
频道约定
你可能已经注意到,上面模型示例中的 broadcastOn 方法没有返回 Channel 实例。相反,直接返回了 Eloquent 模型。如果你的模型的 broadcastOn 方法返回了一个 Eloquent 模型实例(或包含在方法返回的数组中),Laravel 将自动使用模型的类名和主键标识符作为频道名,为模型实例化一个私有频道实例。
因此,一个具有 id 为 1 的 App\Models\User 模型将被转换为一个 Illuminate\Broadcasting\PrivateChannel 实例,名称为 App.Models.User.1。当然,除了从模型的 broadcastOn 方法返回 Eloquent 模型实例外,你还可以返回完整的 Channel 实例,以便完全控制模型的频道名称:
use Illuminate\Broadcasting\PrivateChannel;
/**
* 获取模型事件应广播到的频道。
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(string $event): array
{
return [
new PrivateChannel('user.'.$this->id)
];
}如果你打算从模型的 broadcastOn 方法显式返回一个频道实例,你可以将一个 Eloquent 模型实例传递给频道的构造函数。这样做时,Laravel 将使用上面讨论的模型频道约定将 Eloquent 模型转换为频道名称字符串:
return [new Channel($this->user)];如果你需要确定模型的频道名称,你可以在任何模型实例上调用 broadcastChannel 方法。例如,对于具有 id 为 1 的 App\Models\User 模型,此方法返回字符串 App.Models.User.1:
$user->broadcastChannel();事件约定
由于模型广播事件不与你的应用程序的 App\Events 目录中的“实际”事件相关联,因此它们根据约定被分配一个名称和负载。Laravel 的约定是使用模型的类名(不包括命名空间)和触发广播的模型事件名称来广播该事件。
因此,例如,对 App\Models\Post 模型的更新将作为 PostUpdated 广播到你的客户端应用程序,其负载如下:
{
"model": {
"id": 1,
"title": "我的第一篇文章"
...
},
...
"socket": "someSocketId"
}App\Models\User 模型的删除将广播一个名为 UserDeleted 的事件。
如果你愿意,可以通过向你的模型添加一个 broadcastAs 和 broadcastWith 方法来定义自定义的广播名称和负载。这些方法接收正在发生的模型事件/操作的名称,允许你为每个模型操作自定义事件的名称和负载。如果 broadcastAs 方法返回 null,Laravel 将在广播事件时使用上面讨论的模型广播事件名称约定:
/**
* 模型事件的广播名称。
*/
public function broadcastAs(string $event): string|null
{
return match ($event) {
'created' => 'post.created',
default => null,
};
}
/**
* 获取要广播的模型数据。
*
* @return array<string, mixed>
*/
public function broadcastWith(string $event): array
{
return match ($event) {
'created' => ['title' => $this->title],
default => ['model' => $this],
};
}监听模型广播
一旦你向模型添加了 BroadcastsEvents trait 并定义了模型的 broadcastOn 方法,你就可以开始在你的客户端应用程序中监听广播的模型事件了。开始之前,你可能希望查阅关于监听事件的完整文档。
首先,使用 private 方法获取一个频道实例,然后调用 listen 方法来监听指定事件。通常,传递给 private 方法的频道名称应与 Laravel 的模型广播约定相对应。
一旦你获得了频道实例,就可以使用 listen 方法来监听特定事件。由于模型广播事件不与你的应用程序的 App\Events 目录中的“实际”事件相关联,因此事件名称必须以前缀 . 开头,以表明它不属于特定命名空间。每个模型广播事件都有一个 model 属性,其中包含模型的所有可广播属性:
Echo.private(`App.Models.User.${this.user.id}`)
.listen('.UserUpdated', (e) => {
console.log(e.model);
});使用 React 或 Vue
如果你使用的是 React 或 Vue,你可以使用 Laravel Echo 附带的 useEchoModel 钩子轻松监听模型广播:
import { useEchoModel } from "@laravel/echo-react";
useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model);
});<script setup lang="ts">
import { useEchoModel } from "@laravel/echo-vue";
useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model);
});
</script>你还可以指定模型事件负载数据的类型,提供更大的类型安全性和编辑便利性:
type User = {
id: number;
name: string;
email: string;
};
useEchoModel<User, "App.Models.User">("App.Models.User", userId, ["UserUpdated"], (e) => {
console.log(e.model.id);
console.log(e.model.name);
});客户端事件
NOTE
当使用 Pusher Channels 时,你必须在你应用程序仪表板的“应用程序设置”部分中启用“客户端事件”选项,才能发送客户端事件。
有时你可能希望向其他连接的客户端广播一个事件,而完全不经过你的 Laravel 应用程序。这对于诸如“正在输入”通知之类的事情特别有用,当你想提醒你应用程序的用户另一个用户正在给定屏幕上输入消息时。
要广播客户端事件,你可以使用 Echo 的 whisper 方法:
Echo.private(`chat.${roomId}`)
.whisper('typing', {
name: this.user.name
});import { useEcho } from "@laravel/echo-react";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().whisper('typing', { name: user.name });<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().whisper('typing', { name: user.name });
</script>要监听客户端事件,你可以使用 listenForWhisper 方法:
Echo.private(`chat.${roomId}`)
.listenForWhisper('typing', (e) => {
console.log(e.name);
});import { useEcho } from "@laravel/echo-react";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().listenForWhisper('typing', (e) => {
console.log(e.name);
});<script setup lang="ts">
import { useEcho } from "@laravel/echo-vue";
const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => {
console.log('Chat event received:', e);
});
channel().listenForWhisper('typing', (e) => {
console.log(e.name);
});
</script>通知
通过将事件广播与通知结合使用,你的 JavaScript 应用程序可以在新通知出现时接收它们,而无需刷新页面。开始之前,请务必阅读有关使用广播通知频道的文档。
一旦你配置了一个通知使用广播频道,你就可以使用 Echo 的 notification 方法监听广播事件。请记住,频道名称应与接收通知的实体的类名匹配:
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});import { useEchoModel } from "@laravel/echo-react";
const { channel } = useEchoModel('App.Models.User', userId);
channel().notification((notification) => {
console.log(notification.type);
});<script setup lang="ts">
import { useEchoModel } from "@laravel/echo-vue";
const { channel } = useEchoModel('App.Models.User', userId);
channel().notification((notification) => {
console.log(notification.type);
});
</script>在此示例中,通过 broadcast 频道发送给 App\Models\User 实例的所有通知都将由该回调接收。你的应用程序的 routes/channels.php 文件中包含了一个针对 App.Models.User.{id} 频道的频道授权回调。
停止监听通知
如果你希望在不离开频道的情况下停止监听通知,可以使用 stopListeningForNotification 方法:
const callback = (notification) => {
console.log(notification.type);
}
// 开始监听...
Echo.private(`App.Models.User.${userId}`)
.notification(callback);
// 停止监听(回调必须相同)...
Echo.private(`App.Models.User.${userId}`)
.stopListeningForNotification(callback);