Skip to content

广播系统

简介

在许多现代 Web 应用程序中,WebSockets 被用来实现实时、即时更新的用户界面。当服务器上的某些数据被更新时,通常会通过 WebSocket 连接向客户端发送一条消息。WebSockets 提供了一种更有效的替代方案,无需持续轮询应用程序服务器以获取数据更改。

例如,假设你的应用程序能够将用户数据导出为 CSV 文件并通过电子邮件发送给他们。但是,创建这个 CSV 文件需要几分钟时间,所以你选择在 队列作业 中创建和发送 CSV。当 CSV 创建完成并通过电子邮件发送给用户后,我们可以使用事件广播来分发一个 App\Events\UserDataExported 事件,该事件会被应用程序的 JavaScript 接收。一旦接收到事件,我们就可以向用户显示一条消息,告知他们的 CSV 已通过电子邮件发送,而无需用户刷新页面。

为了帮助你构建这些类型的功能,Laravel 使得通过 WebSocket 连接"广播"你的服务器端 Laravel 事件变得很容易。广播你的 Laravel 事件允许你在服务器端 Laravel 应用程序和客户端 JavaScript 应用程序之间共享相同的事件名称和数据。

广播背后的核心概念很简单:客户端在前端连接到命名的频道,而你的 Laravel 应用程序在后端向这些频道广播事件。这些事件可以包含你希望提供给前端的任何额外数据。

支持的驱动程序

默认情况下,Laravel 包含三个服务器端广播驱动程序供你选择:Laravel ReverbPusher ChannelsAbly

NOTE

在深入了解事件广播之前,请确保你已阅读过 Laravel 关于 事件和监听器 的文档。

服务器端安装

要开始使用 Laravel 的事件广播,我们需要在 Laravel 应用程序中进行一些配置,并安装几个包。

事件广播是通过服务器端广播驱动程序完成的,该驱动程序广播你的 Laravel 事件,以便 Laravel Echo(一个 JavaScript 库)可以在浏览器客户端接收它们。别担心 - 我们将逐步介绍安装过程的每个部分。

配置

你的应用程序的所有事件广播配置都存储在 config/broadcasting.php 配置文件中。如果你的应用程序中不存在此目录,不用担心;当你运行 install:broadcasting Artisan 命令时,它将被创建。

Laravel 默认支持几个广播驱动程序:Laravel ReverbPusher ChannelsAbly 以及用于本地开发和调试的 log 驱动程序。此外,还包括一个 null 驱动程序,允许你在测试期间禁用广播。config/broadcasting.php 配置文件中包含了每个驱动程序的配置示例。

安装

默认情况下,新的 Laravel 应用程序中并未启用广播。你可以使用 install:broadcasting Artisan 命令启用广播:

shell
php artisan install:broadcasting

install:broadcasting 命令将创建 config/broadcasting.php 配置文件。此外,该命令还会创建 routes/channels.php 文件,你可以在其中注册应用程序的广播授权路由和回调。

队列配置

在广播任何事件之前,你应该首先配置并运行一个 队列工作进程。所有事件广播都是通过队列作业完成的,以确保你的应用程序的响应时间不会受到事件广播的严重影响。

Reverb

运行 install:broadcasting 命令时,系统会提示你安装 Laravel Reverb。当然,你也可以使用 Composer 包管理器手动安装 Reverb。

sh
composer require laravel/reverb

安装包后,你可以运行 Reverb 的安装命令来发布配置、添加 Reverb 所需的环境变量,并在你的应用程序中启用事件广播:

sh
php artisan reverb:install

你可以在 Reverb 文档 中找到详细的 Reverb 安装和使用说明。

Pusher Channels

如果你计划使用 Pusher Channels 广播你的事件,你应该使用 Composer 包管理器安装 Pusher Channels PHP SDK:

shell
composer require pusher/pusher-php-server

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Pusher Channels 凭据。这个文件中已经包含了一个 Pusher Channels 配置示例,允许你快速指定你的密钥、密钥和应用程序 ID。通常,你应该在应用程序的 .env 文件中配置你的 Pusher Channels 凭据:

ini
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:

ini
BROADCAST_CONNECTION=pusher

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

如果你计划使用 Ably 广播你的事件,你应该使用 Composer 包管理器安装 Ably PHP SDK:

shell
composer require ably/ably-php

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Ably 凭据。这个文件中已经包含了一个 Ably 配置示例,允许你快速指定你的密钥。通常,这个值应该通过 ABLY_KEY 环境变量 设置:

ini
ABLY_KEY=your-ably-key

然后,在应用程序的 .env 文件中将 BROADCAST_CONNECTION 环境变量设置为 ably:

ini
BROADCAST_CONNECTION=ably

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

客户端安装

Reverb

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。你可以通过 NPM 包管理器安装 Echo。在这个例子中,我们还将安装 pusher-js 包,因为 Reverb 使用 Pusher 协议进行 WebSocket 订阅、频道和消息:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。在 Laravel 框架附带的 resources/js/bootstrap.js 文件底部是一个很好的位置。默认情况下,这个文件中已经包含了一个 Echo 配置示例 - 你只需要取消注释并将 broadcaster 配置选项更新为 reverb:

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,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

接下来,你应该编译应用程序的资源:

shell
npm run build

WARNING

Laravel Echo reverb 广播器需要 laravel-echo v1.16.0+。

Pusher Channels

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Pusher:

js
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
});

接下来,你应该在应用程序的 .env 文件中为 Pusher 环境变量定义适当的值。如果这些变量在你的 .env 文件中不存在,你应该添加它们:

ini
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
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 配置后,你可以编译应用程序的资源:

shell
npm run build

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

使用现有的客户端实例

如果你已经有一个预配置的 Pusher Channels 客户端实例,希望 Echo 使用它,你可以通过 client 配置选项将其传递给 Echo:

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

const options = {
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
}

window.Echo = new Echo({
    ...options,
    client: new Pusher(options.key, options)
});

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

在继续之前,你应该在 Ably 应用程序设置的"Protocol Adapter Settings"部分启用 Pusher 协议支持。

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Ably:

js
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,
});

你可能已经注意到我们的 Ably Echo 配置引用了一个 VITE_ABLY_PUBLIC_KEY 环境变量。这个变量的值应该是你的 Ably 公钥。你的公钥是 Ably 密钥中 : 字符之前的部分。

根据你的需求调整 Echo 配置后,你可以编��应用程序的资源:

shell
npm run dev

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

概念概述

Laravel 的事件广播允许你使用基于驱动程序的方法将服务器端 Laravel 事件广播到客户端 JavaScript 应用程序。目前,Laravel 提供了 Pusher ChannelsAbly 驱动程序。使用 Laravel Echo JavaScript 包可以轻松地在客户端使用这些事件。

事件通过"频道"广播,这些频道可以指定为公共或私有。任何访问你应用程序的人都可以订阅公共频道,无需任何身份验证或授权;但是,要订阅私有频道,用户必须经过身份验证并获得授权才能监听该频道。

广播系统

简介

在许多现代 Web 应用程序中,WebSockets 被用来实现实时、即时更新的用户界面。当服务器上的某些数据被更新时,通常会通过 WebSocket 连接向客户端发送一条消息。WebSockets 提供了一种更有效的替代方案,无需持续轮询应用程序服务器以获取数据更改。

例如,假设你的应用程序能够将用户数据导出为 CSV 文件并通过电子邮件发送给他们。但是,创建这个 CSV 文件需要几分钟时间,所以你选择在 队列作业 中创建和发送 CSV。当 CSV 创建完成并通过电子邮件发送给用户后,我们可以使用事件广播来分发一个 App\Events\UserDataExported 事件,该事件会被应用程序的 JavaScript 接收。一旦接收到事件,我们就可��向用户显示一条消息,告知他们的 CSV 已通过电子邮件发送,而无需用户刷新页面。

为了帮助你构建这些类型的功能,Laravel 使得通过 WebSocket 连接"广播"你的服务器端 Laravel 事件变得很容易。广播你的 Laravel 事件允许你在服务器端 Laravel 应用程序和客户端 JavaScript 应用程序之间共享相同的事件名称和数据。

广播背后的核心概念很简单:客户端在前端连接到命名的频道,而你的 Laravel 应用程序在后端向这些频道广播事件。这些事件可以包含你希望提供给前端的任何额外数据。

支持的驱动程序

默认情况下,Laravel 包含三个服务器端广播驱动程序供你选择:Laravel ReverbPusher ChannelsAbly

NOTE

在深入了解事件广播之前,请确保你已阅读过 Laravel 关于 事件和监听器 的文档。

服务器端安装

要开始使用 Laravel 的事件广播,我们需要在 Laravel 应用程序中进行一些配置,并安装几个包。

事件广播是通过服务器端广播驱动程序完成的,该驱动程序广播你的 Laravel 事件,以便 Laravel Echo(��个 JavaScript 库)可以在浏览器客户端接收它们。别担心 - 我们将逐步介绍安装过程的每个部分。

配置

你的应用程序的所有事件广播配置都存储在 config/broadcasting.php 配置文件中。如果你的应用程序中不存在此目录,不用担心;当你运行 install:broadcasting Artisan 命令时,它将被创建。

Laravel 默认支持几个广播驱动程序:Laravel ReverbPusher ChannelsAbly 以及用于本地开发和调试的 log 驱动程序。此外,还包括一个 null 驱动程序,允许你在测试期间禁用广播。config/broadcasting.php 配置文件中包含了每个驱动程序的配置示例。

安装

默认情况下,新的 Laravel 应用程序中并未启用广播。你可以使用 install:broadcasting Artisan 命令启用广播:

shell
php artisan install:broadcasting

install:broadcasting 命令将创建 config/broadcasting.php 配置文件。此外,该命令还会创建 routes/channels.php 文件,你可以在其中注册应用程序的广播授权路由和回调。

队列配置

在广播任何事件之前,你应该首先配置并运行一个 队列工作进程。所有事件广播都是通过队列作业完成的,以确保你的应用程序的响应时间不会受到事件广播的严重影响。

Reverb

运行 install:broadcasting 命令时,系统会提示你安装 Laravel Reverb。当然,你也可以使用 Composer 包管理器手动安装 Reverb。

sh
composer require laravel/reverb

安装包后,你可以运行 Reverb 的安装命令来发布配置、添加 Reverb 所需的环境变量,并在你的应用程序中启用事件广播:

sh
php artisan reverb:install

你可以在 Reverb 文档 中找到详细的 Reverb 安装和使用说明。

Pusher Channels

如果你计划使用 Pusher Channels 广播你的事件,你应该使用 Composer 包管理器安装 Pusher Channels PHP SDK:

shell
composer require pusher/pusher-php-server

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Pusher Channels 凭据。这个文件中已经包含了一个 Pusher Channels 配置示例,允许你快速指定你的密钥、密钥和应用程序 ID。通常,你应该在应用程序的 .env 文件中配置你的 Pusher Channels 凭据:

ini
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:

ini
BROADCAST_CONNECTION=pusher

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

如果你计划使用 Ably 广播你的事件,你应该使用 Composer 包管理器安装 Ably PHP SDK:

shell
composer require ably/ably-php

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Ably 凭据。这个文件中已经包含了一个 Ably 配置示例,允许你快速指定你的密钥。通常,这个值应该通过 ABLY_KEY 环境变量 设置:

ini
ABLY_KEY=your-ably-key

然后,在应用程序的 .env 文件中将 BROADCAST_CONNECTION 环境变量设置为 ably:

ini
BROADCAST_CONNECTION=ably

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

客户端安装

Reverb

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。你可以通过 NPM 包管理器安装 Echo。在这个例子中,我们还将安装 pusher-js 包,因为 Reverb 使用 Pusher 协议进行 WebSocket 订阅、频道和消息:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。在 Laravel 框架附带的 resources/js/bootstrap.js 文件底部是一个很好的位置。默认情况下,这个文件中已经包含了一个 Echo 配置示例 - 你只需要取消注释并将 broadcaster 配置选项更新为 reverb:

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,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

接下来,你应该编译应用程序的资源:

shell
npm run build

WARNING

Laravel Echo reverb 广播器需要 laravel-echo v1.16.0+。

Pusher Channels

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Pusher:

js
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
});

接下来,你应该在应用程序的 .env 文件中为 Pusher 环境变量定义适当的值。如果这些变量在你的 .env 文件中不存在,你应该添加它们:

ini
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
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 配置后,你可以编译应用程序的资源:

shell
npm run build

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

使用现有的客户端实例

如果你已经有一个预配置的 Pusher Channels 客户端实例,希望 Echo 使用它,你可以通过 client 配置选项将其传递给 Echo:

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

const options = {
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
}

window.Echo = new Echo({
    ...options,
    client: new Pusher(options.key, options)
});

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

在继续之前,你应该在 Ably 应用程序设置的"Protocol Adapter Settings"部分启用 Pusher 协议支持。

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Ably:

js
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,
});

你可能已经注意到我们的 Ably Echo 配置引用了一个 VITE_ABLY_PUBLIC_KEY 环境变量。这个变量的值应该是你的 Ably 公钥。你的公钥是 Ably 密钥中 : 字符之前的部分。

根据你的需求调整 Echo 配置后,你可以编译应用程序的资源:

shell
npm run dev

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

概念概述

Laravel 的事件广播允许你使用基于驱动程序的方法将服务器端 Laravel 事件广播到客户端 JavaScript 应用程序。目前,Laravel 提供了 Pusher ChannelsAbly 驱动程序。使用 Laravel Echo JavaScript 包可以轻松地在客户端使用这些事件。

事件通过"频道"广播,这些频道可以指定为公共或私有。任何访问你���用程序的人都可以订阅公共频道,无需任何身份验证或授权;但是,要订阅私有频道,用户必须经过身份验证并获得授权才能监听该频道。

使用示例应用程序

在深入研究事件广播的每个组件之前,让我们以一个电子商务商店为例进行高层次的概述。

在我们的应用程序中,假设我们有一个页面允许用户查看他们订单的发货状态。我们还假设当应用程序处理发货状态更新时,会触发一个 OrderShipmentStatusUpdated 事件:

php
    use App\Events\OrderShipmentStatusUpdated;

    OrderShipmentStatusUpdated::dispatch($order);

ShouldBroadcast 接口

当用户查看他们的某个订单时,我们不希望他们必须刷新页面来查看状态更新。相反,我们希望在创建更新时将其广播到应用程序。因此,我们需要用 ShouldBroadcast 接口标记 OrderShipmentStatusUpdated 事件。这将指示 Laravel 在触发事件时广播该事件:

php
    <?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
    {
        /**
         * The order instance.
         *
         * @var \App\Models\Order
         */
        public $order;
    }

ShouldBroadcast 接口要求我们的事件定义一个 broadcastOn 方法。这个方法负责返回事件应该广播的频道。生成的事件类上已经定义了这个方法的空存根,所以我们只需要填写它的详细信息。我们只希望订单的创建者能够查看状态更新,所以我们将在与订单相关的私有频道上广播事件:

php
    use Illuminate\Broadcasting\Channel;
    use Illuminate\Broadcasting\PrivateChannel;

    /**
     * Get the channel the event should broadcast on.
     */
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.'.$this->order->id);
    }

如果你希望事件在多个频道上广播,你可以返回一个 array:

php
    use Illuminate\Broadcasting\PrivateChannel;

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('orders.'.$this->order->id),
            // ...
        ];
    }

授权频道

请记住,用户必须被授权才能监听私有频道。我们可以在应用程序的 routes/channels.php 文件中定义我们的频道授权规则。在这个例子中,我们需要验证任何试图监听私有 orders.1 频道的用户实际上是订单的创建者:

php
    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 方法接受两个参数:频道的名称和一个回调函数,该函数返回 truefalse,表示用户是否被授权监听该频道。

所有授权回调都接收当前认证的用户作为其第一个参数,以及任何额外的通配符参数作为其后续参数。在这个例子中,我们使用 {orderId} 占位符来表示频道名称的"ID"部分是一个通配符。

监听事件广播

接下来,剩下的就是在我们的 JavaScript 应用程序中监听事件。我们可以使用 Laravel Echo 来做到这一点。首先,我们将使用 private 方法订阅私有频道。然后,我们可以使用 listen 方法来监听 OrderShipmentStatusUpdated 事件。默认情况下,事件的所有公共属性都将包含在广播事件中:

js
Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

定义广播事件

要通知 Laravel 某个给定的事件应该被广播,你必须在事件类上实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast 接口。框架生成的所有事件类都已经导入了这个接口,所以你可以轻松地将它添加到任何你的事件中。

ShouldBroadcast 接口要求你实现一个单一的方法:broadcastOnbroadcastOn 方法应该返回事件应该广播的频道或频道数组。这些频道应该是 ChannelPrivateChannelPresenceChannel 的实例。Channel 实例代表任何用户都可以订阅的公共频道,而 PrivateChannelsPresenceChannels 代表需要 频道授权 的私有频道:

php
    <?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;

        /**
         * Create a new event instance.
         */
        public function __construct(
            public User $user,
        ) {}

        /**
         * Get the channels the event should broadcast on.
         *
         * @return array<int, \Illuminate\Broadcasting\Channel>
         */
        public function broadcastOn(): array
        {
            return [
                new PrivateChannel('user.'.$this->user->id),
            ];
        }
    }

实现 ShouldBroadcast 接口后,你只需要像平常一样 触发事件。一旦事件被触发,一个 队列作业 将自动使用你指定的广播驱动程序广播事件。

广播名称

默认情况下,Laravel 将使用事件的类名广播事件。但是,你可以通过在事件上定义一个 broadcastAs 方法来自定义广播名称:

php
    /**
     * The event's broadcast name.
     */
    public function broadcastAs(): string
    {
        return 'server.created';
    }

如果你使用 broadcastAs 方法自定义广播名称,你应该确保用一个前导 . 字符注册你的监听器。这将指示 Echo 不要将应用程序的命名空间添加到事件中:

php
    .listen('.server.created', function (e) {
        ....
    });

广播数据

当一个事件被广播时,它的所有 public 属性都会自动序列化并作为事件的有效载荷进行广播,允许你从 JavaScript 应用程序访问其任何公共数据。因此,例如,如果你的事件有一个包含 Eloquent 模型的单个公共 $user 属性,事件的广播有效载荷将是:

json
{
    "user": {
        "id": 1,
        "name": "Patrick Stewart"
        ...
    }
}

然而,如果你希望对广播有效载荷有更细粒度的控制,你可以向事件添加一个 broadcastWith 方法。这个方法应该返回你希望作为事件有效载荷广播的数据数组:

php
    /**
     * Get the data to broadcast.
     *
     * @return array<string, mixed>
     */
    public function broadcastWith(): array
    {
        return ['id' => $this->user->id];
    }

广播队列

默认情况下,每个广播事件都被放置在 queue.php 配置文件中指定的默认队列连接的默认队列上。你可以通过在事件类上定义 connectionqueue 属性来自定义广播器使用的队列连接和名称:

php
    /**
     * The name of the queue connection to use when broadcasting the event.
# 广播系统

- [简介](#introduction)
- [服务器端安装](#server-side-installation)
    - [配置](#configuration)
    - [Reverb](#reverb)
    - [Pusher Channels](#pusher-channels)
    - [Ably](#ably)
- [客户端安装](#client-side-installation)
    - [Reverb](#client-reverb)
    - [Pusher Channels](#client-pusher-channels)
    - [Ably](#client-ably)
- [概念概述](#concept-overview)
    - [使用示例应用程序](#using-example-application)
- [定义广播事件](#defining-broadcast-events)
    - [广播名称](#broadcast-name)
    - [广播数据](#broadcast-data)
    - [广播队列](#broadcast-queue)
    - [广播条件](#broadcast-conditions)
    - [广播和数据库事务](#broadcasting-and-database-transactions)
- [频道授权](#authorizing-channels)
    - [定义授权回调](#defining-authorization-callbacks)
    - [定义频道类](#defining-channel-classes)
- [广播事件](#broadcasting-events)
    - [只广播给其他人](#only-to-others)
    - [自定义连接](#customizing-the-connection)
    - [匿名事件](#anonymous-events)
- [接收广播](#receiving-broadcasts)
    - [监听事件](#listening-for-events)
    - [离开频道](#leaving-a-channel)
    - [命名空间](#namespaces)
- [在线频道](#presence-channels)
    - [授权在线频道](#authorizing-presence-channels)
    - [加入在线频道](#joining-presence-channels)
    - [广播到在线频道](#broadcasting-to-presence-channels)
- [模型广播](#model-broadcasting)
    - [模型广播约定](#model-broadcasting-conventions)
    - [监听模型广播](#listening-for-model-broadcasts)
- [客户端事件](#client-events)
- [通知](#notifications)

{#introduction}
## 简介

在许多现代 Web 应用程序中,WebSockets 被用来实现实时、即时更新的用户界面。当服务器上的某些数据被更新时,通常会通过 WebSocket 连接向客户端发送一条消息。WebSockets 提供了一种更有效的替代方案,无需持续轮询应用程序服务器以获取数据更改。

例如,假设你的应用程序能够将用户数据导出为 CSV 文件并通过电子邮件发送给他们。但是,创建这个 CSV 文件需要几分钟时间,所以你选择在 [队列作业](/laravel11/zh/queues) 中创建和发送 CSV。当 CSV 创建完成并通过电子邮件发送给用户后,我们可以使用事件广播来分发一个 `App\Events\UserDataExported` 事件,该事件会被应用程序的 JavaScript 接收。一旦接收到事件,我们就可以向用户显示一条消息,告知他们的 CSV 已通过电子邮件发送,而无需用户刷新页面。

为了帮助你构建这些类型的功能,Laravel 使得通过 WebSocket 连接"广播"你的服务器端 Laravel [事件](/laravel11/zh/events)变得很容易。广播你的 Laravel 事件允许你在服务器端 Laravel 应用程序和客户端 JavaScript 应用程序之间共享相同的事件名称和数据。

广播背后的核心概念很简单:客户端在前端连接到命名的频道,而你的 Laravel 应用程序在后端向这些频道广播事件。这些事件可以包含你希望提供给前端的任何额外数据。

{#supported-drivers}
#### 支持的驱动程序

默认情况下,Laravel 包含三个服务器端广播驱动程序供你选择:[Laravel Reverb](https://reverb.laravel.com)、[Pusher Channels](https://pusher.com/channels) 和 [Ably](https://ably.com)。

> [!NOTE]  
> 在深入了解事件广播之前,请确保你已阅读过 Laravel 关于 [事件和监听器](/laravel11/zh/events) 的文档。

{#server-side-installation}
## 服务器端安装

要开始使用 Laravel 的事件广播,我们需要在 Laravel 应用程序中进行一些配置,并安装几个包。

事件广播是通过服务器端广播驱动程序完成的,该驱动程序广播你的 Laravel 事件,以便 Laravel Echo(一个 JavaScript 库)可以在浏览器客户端接收它们。别担心 - 我们将逐步介绍安装过程的每个部分。

{#configuration}
### 配置

你的应用程序的所有事件广播配置都存储在 `config/broadcasting.php` 配置文件中。如果你的应用程序中不存在此目录,不用担心;当你运行 `install:broadcasting` Artisan 命令时,它将被创建。

Laravel 默认支持几个广播驱动程序:[Laravel Reverb](/laravel11/zh/reverb)、[Pusher Channels](https://pusher.com/channels)、[Ably](https://ably.com) 以及用于本地开发和调试的 `log` 驱动程序。此外,还包括一个 `null` 驱动程序,允许你在测试期间禁用广播。`config/broadcasting.php` 配置文件中包含了每个驱动程序的配置示例。

{#installation}
#### 安装

默认情况下,新的 Laravel 应用程序中并未启用广播。你可以使用 `install:broadcasting` Artisan 命令启用广播:

```shell
php artisan install:broadcasting

install:broadcasting 命令将创建 config/broadcasting.php 配置文件。此外,该命令还会创建 routes/channels.php 文件,你可以在其中注册应用程序的广播授权路由和回调。

队列配置

在广播任何事件之前,你应该首先配置并运行一个 队列工作进程。所有事件广播都是通过队列作业完成的,以确保你的应用程序的响应时间不会受到事件广播的严重影响。

Reverb

运行 install:broadcasting 命令时,系统会提示你安装 Laravel Reverb。当然,你也可以使用 Composer 包管理器手动安装 Reverb。

sh
composer require laravel/reverb

安装包后,你可以运行 Reverb 的安装命令来发布配置、添加 Reverb 所需的环境变量,并在你的应用程序中启用事件广播:

sh
php artisan reverb:install

你可以在 Reverb 文档 中找到详细的 Reverb 安装和使用说明。

Pusher Channels

如果你计划使用 Pusher Channels 广播你的事件,你应该使用 Composer 包管理器安装 Pusher Channels PHP SDK:

shell
composer require pusher/pusher-php-server

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Pusher Channels 凭据。这个文件中已经包含了一个 Pusher Channels 配置示例,允许你快速指定你的密钥、密钥和应用程序 ID。通常,你应该在应用程序的 .env 文件中配置你的 Pusher Channels 凭据:

ini
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:

ini
BROADCAST_CONNECTION=pusher

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

如果你计划使用 Ably 广播你的事件,你应该使用 Composer 包管理器安装 Ably PHP SDK:

shell
composer require ably/ably-php

接下来,你应该在 config/broadcasting.php 配置文件中配置你的 Ably 凭据。这个文件中已经包含了一个 Ably 配置示例,允许你快速指定你的密钥。通常,这个值应该通过 ABLY_KEY 环境变量 设置:

ini
ABLY_KEY=your-ably-key

然后,在应用程序的 .env 文件中将 BROADCAST_CONNECTION 环境变量设置为 ably:

ini
BROADCAST_CONNECTION=ably

最后,你已准备好安装和配置 Laravel Echo,它将在客户端接收广播事件。

客户端安装

Reverb

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。你可以通过 NPM 包管理器安装 Echo。在这个例子中,我们还将安装 pusher-js 包,因为 Reverb 使用 Pusher 协议进行 WebSocket 订阅、频道和消息:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。在 Laravel 框架附带的 resources/js/bootstrap.js 文件底部是一个很好的位置。默认情况下,这个文件中已经包含了一个 Echo 配置示例 - 你只需要取消注释并将 broadcaster 配置选项更新为 reverb:

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,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

接下来,你应该编译应用程序的资源:

shell
npm run build

WARNING

Laravel Echo reverb 广播器需要 laravel-echo v1.16.0+。

Pusher Channels

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Pusher:

js
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
});

接下来,你应该在应用程序的 .env 文件中为 Pusher 环境变量定义适当的值。如果这些变量在你的 .env 文件中不存在,你应该添加它们:

ini
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
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 配置后,你可以编译应用程序的资源:

shell
npm run build

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

使用现有的客户端实例

如果你已经有一个预配置的 Pusher Channels 客户端实例,希望 Echo 使用它,你可以通过 client 配置选项将其传递给 Echo:

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

const options = {
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
}

window.Echo = new Echo({
    ...options,
    client: new Pusher(options.key, options)
});

Ably

NOTE

下面的文档讨论了如何在"Pusher 兼容性"模式下使用 Ably。然而,Ably 团队推荐并维护了一个广播器和 Echo 客户端,能够利用 Ably 提供的独特功能。有关使用 Ably 维护的驱动程序的更多信息,请 参阅 Ably 的 Laravel 广播器文档

Laravel Echo 是一个 JavaScript 库,它使订阅频道和监听服务器端广播驱动程序广播的事件变得非常简单。Echo 还利用 pusher-js NPM 包来实现 Pusher 协议的 WebSocket 订阅、频道和消息。

install:broadcasting Artisan 命令会自动为你安装 laravel-echopusher-js 包;但是,你也可以通过 NPM 手动安装这些包:

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

在继续之前,你应该在 Ably 应用程序设置的"Protocol Adapter Settings"部分启用 Pusher 协议支持。

安装 Echo 后,你就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例了。install:broadcasting 命令会在 resources/js/echo.js 创建一个 Echo 配置文件;但是,该文件中的默认配置是为 Laravel Reverb 设计的。你可以复制下面的配置来将配置转换为 Ably:

js
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,
});

你可能已经注意到我们的 Ably Echo 配置引用了一个 VITE_ABLY_PUBLIC_KEY 环境变量。这个变量的值应该是你的 Ably 公钥。你的公钥是 Ably 密钥中 : 字符之前的部分。

根据你的需求调整 Echo 配置后,你可以编译应用程序的资源:

shell
npm run dev

NOTE

要了解更多关于编译应用程序 JavaScript 资源的信息,请参阅 Vite 文档。

概念概述

Laravel 的事件广播允许你使用基于驱动程序的方法将服务器端 Laravel 事件广播到客户端 JavaScript 应用程序。目前,Laravel 提供了 Pusher ChannelsAbly 驱动程序。使用 Laravel Echo JavaScript 包可以轻松地在客户端使用这些事件。

事件通过"频道"广播,这些频道可以指定为公共或私有。任何访问你应用程序的人都可以订阅公共频道,无需任何身份验证或授权;但是,要订阅私有频道,用户必须经过身份验证并获得授权才能监听该频道。

使用示例应用程序

在深入研究事件广播的每个组件之前,让我们以一个电子商务商店为例进行高层次的概述。

在我们的应用程序中,假设我们有一个页面允许用户查看他们订单的发货状态。我们还假设当应用程序处理发货状态更新时,会触发一个 OrderShipmentStatusUpdated 事件:

php
    use App\Events\OrderShipmentStatusUpdated;

    OrderShipmentStatusUpdated::dispatch($order);

ShouldBroadcast 接口

当用户查看他们的某个订单时,我们不希望他们必须刷新页面来查看状态更新。相反,我们希望在创建更新时将其广播到应用程序。因此,我们需要用 ShouldBroadcast 接口标记 OrderShipmentStatusUpdated 事件。这将指示 Laravel 在触发事件时广播该事件:

php
    <?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;

        /**
         * Create a new event instance.
         */
        public function __construct(
            public User $user,
        ) {}

        /**
         * Get the channels the event should broadcast on.
         *
         * @return array<int, \Illuminate\Broadcasting\Channel>
         */
        public function broadcastOn(): array
        {
            return [
                new PrivateChannel('user.'.$this->user->id),
            ];
        }
    }

实现 ShouldBroadcast 接口后,你只需要像通常一样 触发事件。一旦事件被触发,一个 队列作业 将自动使用你指定的广播驱动程序广播该事件。

广播名称

默认情况下,Laravel 将使用事件的类名广播事件。但是,你可以通过在事件上定义 broadcastAs 方法来自定义广播名称:

php
    /**
     * The event's broadcast name.
     */
    public function broadcastAs(): string
    {
        return 'server.created';
    }

如果你使用 broadcastAs 方法自定义广播名称,你应该确保使用以 . 字符开头的监听器注册你的监听器。这将指示 Echo 不要在事件名称前添加应用程序的命名空间:

php
    .listen('.server.created', function (e) {
        ....
    });

广播数据

当事件被广播时,所有的 public 属性都将自动序列化并作为事件的有效负载广播,允许你访问其任何公共数据。因此,例如,如果你的事件有一个单一的公共 $user 属性,包含一个 Eloquent 模型,那么事件的广播有效负载将是:

json
{
    "user": {
        "id": 1,
        "name": "Patrick Stewart"
        ...
    }
}

但是,如果你希望对广播有效负载有更精细的控制,你可以在事件上添加一个 broadcastWith 方法。该方法应返回你希望作为事件有效负载广播的数据数组:

php
    /**
     * Get the data to broadcast.
     *
     * @return array<string, mixed>
     */
    public function broadcastWith(): array
    {
        return ['id' => $this->user->id];
    }

广播队列

默认情况下,每个广播事件都会放置在 queue.php 配置文件中指定的默认队列连接的默认队列上。你可以通过在事件类上定义 connectionqueue 属性来自定义广播器使用的队列连接和名称:

php
    /**
     * The name of the queue connection to use when broadcasting the event.
     *
     * @var string
     */
    public $connection = 'redis';

    /**
     * The name of the queue on which to place the broadcasting job.
     *
     * @var string
     */
    public $queue = 'default';

或者,你可以通过在事件上定义 broadcastQueue 方法来自定义队列名称:

php
    /**
     * The name of the queue on which to place the broadcasting job.
     */
    public function broadcastQueue(): string
    {
        return 'default';
    }

如果你想使用 sync 队列而不是默认队列驱动程序来广播你的事件,你可以在事件类上实现 ShouldBroadcastNow 接口而不是 ShouldBroadcast:

php
    <?php

    use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

    class OrderShipmentStatusUpdated implements ShouldBroadcastNow
    {
        // ...
    }

广播条件

有时你希望只有在给定条件为真时才广播你的事件。你可以通过在事件类上添加 broadcastWhen 方法来定义这些条件:

php
    /**
     * Determine if this event should broadcast.
     */
    public function broadcastWhen(): bool
    {
        return $this->order->value > 100;
    }

广播和数据库事务

当在数据库事务中广播事件时,它们可能会在数据库事务提交之前由队列处理。当这种情况发生时,你在数据库事务期间对模型或数据库记录所做的任何更新可能尚未反映在数据库中。此外,在事务中创建的任何模型或数据库记录可能在数据库中不存在。如果你的事件依赖于这些模型,当处理广播事件的作业时可能会发生意外错误。

如果你的队列连接的 after_commit 配置选项设置为 false,你仍然可以指示特定的广播事件应在所有打开的数据库事务都提交后才分发,方法是在事件类上实现 ShouldDispatchAfterCommit 接口:

php
    <?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 路由来处理授权请求。/broadcasting/auth 路由已自动放置在 web 中间件组中。

定义授权回调

接下来,我们需要定义实际确定当前经过身份验证的用户是否可以监听给定频道的逻辑。这是在 routes/channels.php 文件中完成的,该文件是由 install:broadcasting Artisan 命令创建的。在这个文件中,你可以使用 Broadcast::channel 方法注册频道授权回调:

php
    use App\Models\User;

    Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
        return $user->id === Order::findOrNew($orderId)->user_id;
    });

channel 方法接受两个参数:频道名称和一个返回 truefalse 的回调,指示用户是否有权监听该频道。

所有授权回调都会接收当前经过身份验证的用户作为其第一个参数,以及任何额外的通配符参数作为其后续参数。在这个例子中,我们使用 {orderId} 占位符来指示频道名称的 "ID" 部分是一个通配符。

你可以使用 channel:list Artisan 命令查看应用程序的广播授权回调列表:

shell
php artisan channel:list

授权回调模型绑定

就像 HTTP 路由一样,频道路由也可以利用隐式和显式 路由模型绑定。例如,你可以请求一个实际的 Order 模型实例,而不是请求字符串或数字订单 ID:

php
    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 路由模型绑定不同,频道模型绑定不支持自动 隐式模型绑定作用域。但是,这很少是一个问题,因为大多数频道可以基于单个模型的唯一主键进行作用域。

授权回调身份验证

私有和在线广播频道使用你的应用程序的默认身份验证守卫对当前用户进行身份验证。如果用户未经过身份验证,频道授权将自动被拒绝,并且不会执行授权回调。但是,你可以分配多个自定义守卫,以便在必要时对传入请求进行身份验证:

php
    Broadcast::channel('channel', function () {
        // ...
    }, ['guards' => ['web', 'admin']]);

定义频道类

如果你的应用程序正在使用许多不同的频道,你的 routes/channels.php 文件可能会变得很庞大。因此,你可以使用频道类而不是使用闭包来授权频道。要生成频道类,使用 make:channel Artisan 命令。该命令将在 App/Broadcasting 目录中放置一个新的频道类。

shell
php artisan make:channel OrderChannel

接下来,在你的 routes/channels.php 文件中注册你的频道:

php
    use App\Broadcasting\OrderChannel;

    Broadcast::channel('orders.{order}', OrderChannel::class);

最后,你可以在频道类的 join 方法中放置频道授权逻辑。该 join 方法将包含你通常会放在频道授权闭包中的逻辑。你还可以利用频道模型绑定:

php
    <?php

    namespace App\Broadcasting;

    use App\Models\Order;
    use App\Models\User;

    class OrderChannel
    {
        /**
         * Create a new channel instance.
         */
        public function __construct()
        {
            // ...
        }

        /**
         * Authenticate the user's access to the channel.
         */
        public function join(User $user, Order $order): array|bool
        {
            return $user->id === $order->user_id;
        }
    }

NOTE

与 Laravel 中的许多其他类一样,频道类将由 服务容器 自动解析。因此,你可以在频道类的构造函数中类型提示所需的任何依赖项。

广播事件

一旦你定义了一个事件并用 ShouldBroadcast 接口标记它,你只需要使用事件的 dispatch 方法触发该事件。事件分发器会注意到该事件已标记为 ShouldBroadcast 接口,并将该事件排队以进行广播:

php
    use App\Events\OrderShipmentStatusUpdated;

    OrderShipmentStatusUpdated::dispatch($order);

只广播给其他人

在构建使用事件广播的应用程序时,你有时可能需要将事件广播给给定频道的所有订阅者,但不包括当前用户。你可以使用 broadcast 辅助函数和 toOthers 方法来实现这一点:

php
    use App\Events\OrderShipmentStatusUpdated;

    broadcast(new OrderShipmentStatusUpdated($update))->toOthers();

为了更好地理解何时可能需要使用 toOthers 方法,让我们想象一个任务列表应用程序,用户可以通过输入任务名称来创建新任务。为了创建任务,你的应用程序可能会向 /task URL 发出请求,该 URL 会广播任务的创建并返回新任务的 JSON 表示。当你的 JavaScript 应用程序从端点接收响应时,它可能会直接将新任务插入其任务列表中,如下所示:

js
axios.post('/task', task)
    .then((response) => {
        this.tasks.push(response.data);
    });

但是,请记住,我们还广播了任务的创建。如果你的 JavaScript 应用程序也在监听此事件以将任务添加到任务列表,你将在任务列表中有重复的任务:一个来自端点,一个来自广播。你可以使用 toOthers 方法指示广播器不要将事件广播给当前用户来解决此问题。

WARNING

你的事件必须使用 Illuminate\Broadcasting\InteractsWithSockets trait 才能调用 toOthers 方法。

配置

当你初始化 Laravel Echo 实例时,会为连接分配一个 socket ID。如果你正在使用全局 Axios 实例从你的 JavaScript 应用程序发出 HTTP 请求,那么 socket ID 将自动作为 X-Socket-ID 标头附加到所有传出请求中。然后,当你调用 toOthers 方法时,Laravel 将从标头中提取 socket ID,并指示广播器不要将事件广播给任何具有该 socket ID 的连接。

如果你没有使用全局 Axios 实例,你将需要手动配置你的 JavaScript 应用程序,以便在所有传出请求中发送 X-Socket-ID 标头。你可以使用 Echo.socketId 方法获取 socket ID:

js
var socketId = Echo.socketId();

自定义连接

如果你的应用程序与多个广播连接进行交互,并且你想使用除默认广播器之外的广播器广播事件,你可以使用 via 方法指定要将事件推送到哪个连接:

php
    use App\Events\OrderShipmentStatusUpdated;

    broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');

另外,你可以通过在事件的构造函数中调用 broadcastVia 方法来指定事件的广播连接。但在这样做之前,你应该确保事件类使用了 InteractsWithBroadcasting trait:

php
<?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 facade 允许你广播"匿名事件":

php
Broadcast::on('orders.'.$order->id)->send();

上面的例子将广播以下事件:

json
{
    "event": "AnonymousEvent",
    "data": "[]",
    "channel": "orders.1"
}

使用 aswith 方法,你可以自定义事件的名称和数据:

php
Broadcast::on('orders.'.$order->id)
    ->as('OrderPlaced')
    ->with($order)
    ->send();

上面的例子将广播一个类似以下的事件:

json
{
    "event": "OrderPlaced",
    "data": "{ id: 1, total: 100 }",
    "channel": "orders.1"
}

如果你想在私有或存在频道上广播匿名事件,可以使用 privatepresence 方法:

php
Broadcast::private('orders.'.$order->id)->send();
Broadcast::presence('channels.'.$channel->id)->send();

使用 send 方法广播匿名事件会将事件分发到你应用程序的队列进行处理。但是,如果你想立即广播事件,可以使用 sendNow 方法:

php
Broadcast::on('orders.'.$order->id)->sendNow();

要将事件广播给除当前认证用户之外的所有频道订阅者,你可以调用 toOthers 方法:

php
Broadcast::on('orders.'.$order->id)
    ->toOthers()
    ->send();

接收广播

监听事件

一旦你安装并实例化了 Laravel Echo,你就可以开始监听从 Laravel 应用程序广播的事件了。首先,使用 channel 方法获取一个频道实例,然后调用 listen 方法来监听指定的事件:

js
Echo.channel(`orders.${this.order.id}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order.name);
    });

如果你想监听私有频道上的事件,请使用 private 方法。你可以继续链式调用 listen 方法来监听单个频道上的多个事件:

js
Echo.private(`orders.${this.order.id}`)
    .listen(/* ... */)
    .listen(/* ... */)
    .listen(/* ... */);

停止监听事件

如果你想停止监听给定的事件而不离开频道,你可以使用 stopListening 方法:

js
Echo.private(`orders.${this.order.id}`)
    .stopListening('OrderShipmentStatusUpdated')

离开频道

要离开一个频道,你可以在 Echo 实例上调用 leaveChannel 方法:

js
Echo.leaveChannel(`orders.${this.order.id}`);

如果你想离开一个频道及其相关的私有和存在频道,你可以调用 leave 方法:

js
Echo.leave(`orders.${this.order.id}`);

命名空间

你可能已经注意到在上面的例子中,我们没有为事件类指定完整的 App\Events 命名空间。这是因为 Echo 会自动假设事件位于 App\Events 命名空间中。但是,你可以在实例化 Echo 时通过传递 namespace 配置选项来配置根命名空间:

js
window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    namespace: 'App.Other.Namespace'
});

或者,当使用 Echo 订阅事件时,你可以在事件类前加上 . 前缀。这将允许你始终指定完全限定的类名:

js
Echo.channel('orders')
    .listen('.Namespace\\Event\\Class', (e) => {
        // ...
    });

存在频道

存在频道在私有频道的安全基础上,增加了谁订阅了频道的额外功能。这使得构建强大的、协作性的应用程序功能变得容易,比如通知用户另一个用户正在查看同一页面,或列出聊天室中的用户。

授权存在频道

所有存在频道也都是私有频道;因此,用户必须被授权访问它们。但是,在为存在频道定义授权回调时,如果用户被授权加入频道,你不应返回 true。相反,你应该返回一个包含用户数据的数组。

授权回调返回的数据将在你的 JavaScript 应用程序中提供给存在频道事件监听器。如果用户未被授权加入存在频道,你应该返回 falsenull:

php
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 方法外,还允许你订阅 herejoiningleaving 事件。

js
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 方法。当认证端点返回非 200 HTTP 状态码或解析返回的 JSON 出现问题时,将执行 error 方法。

向存在频道广播

存在频道可以像公共或私有频道一样接收事件。以聊天室为例,我们可能想向房间的存在频道广播 NewMessage 事件。为此,我们将从事件的 broadcastOn 方法返回一个 PresenceChannel 实例:

php
/**
 * 获取事件应该广播的频道。
 *
 * @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 方法来监听发送到存在频道的事件:

js
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
<?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 参数。这个参数包含了在模型上发生的事件类型,它的值可能是 createdupdateddeletedtrashedrestored。通过检查这个变量的值,你可以确定模型应该为特定事件广播到哪些频道(如果有的话):

php
/**
 * 获取模型事件应该广播的频道。
 *
 * @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 实例:

php
use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;

/**
 * 为模型创建一个新的可广播模型事件。
 */
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
    return (new BroadcastableModelEventOccurred(
        $this, $event
    ))->dontBroadcastToCurrentUser();
}

模型广播约定

频道约定

你可能已经注意到,上面模型示例中的 broadcastOn 方法没有返回 Channel 实例。相反,直接返回了 Eloquent 模型。如果你的模型的 broadcastOn 方法返回一个 Eloquent 模型实例(或包含在方法返回的数组中),Laravel 将自动为该模型实例化一个私有频道,使用模型的类名和主键标识符作为频道名称。

所以,一个 App\Models\User 模型,其 id1 将被转换为一个 Illuminate\Broadcasting\PrivateChannel 实例,其名称为 App.Models.User.1。当然,除了从你的模型的 broadcastOn 方法返回 Eloquent 模型实例外,你还可以返回完整的 Channel 实例,以便完全控制模型的频道名称:

php
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 模型转换为频道名称字符串:

php
return [new Channel($this->user)];

如果你需要确定一个模型的频道名称,你可以在任何模型实例上调用 broadcastChannel 方法。例如,这个方法对于一个 id1App\Models\User 模型将返回字符串 App.Models.User.1:

php
$user->broadcastChannel()

事件约定

由于模型广播事件与你应用程序的 App\Events 目录中没有"实际"事件相关联,它们被分配了一个名称和一个基于约定的有效负载。Laravel 的约定是使用模型的类名(不包括命名空间)和触发广播的模型事件的名称来广播事件。

所以,例如,对 App\Models\Post 模型的更新将以 PostUpdated 事件的形式广播到你的客户端应用程序,并带有以下有效负载:

json
{
    "model": {
        "id": 1,
        "title": "My first post"
        ...
    },
    ...
    "socket": "someSocketId",
}

删除 App\Models\User 模型将广播一个名为 UserDeleted 的事件。

如果你愿意,你可以通过在你的模型上添加 broadcastAsbroadcastWith 方法来定义自定义的广播名称和有效负载。这些方法接收触发的模型事件/操作的名称,允许你为每个模型操作自定义事件的名称和有效负载。如果 broadcastAs 方法返回 null,Laravel 将使用上面讨论过的模型广播事件名称约定来广播事件:

php
/**
 * 模型事件的广播名称。
 */
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 属性,其中包含模型的所有可广播属性:

js
Echo.private(`App.Models.User.${this.user.id}`)
    .listen('.PostUpdated', (e) => {
        console.log(e.model);
    });

客户端事件

NOTE

当使用 Pusher Channels 时,你必须在 应用程序仪表板 的 "App Settings" 部分启用 "Client Events" 选项,才能发送客户端事件。

有时,你可能希望在根本不触及你的 Laravel 应用程序的情况下,向其他连接的客户端广播一个事件。这在某些情况下可能非常有用,比如"正在输入"通知,你希望在给定屏幕上警告你的应用程序的其他用户另一个用户正在输入消息。

要广播客户端事件,你可以使用 Echo 的 whisper 方法:

js
Echo.private(`chat.${roomId}`)
    .whisper('typing', {
        name: this.user.name
    });

要监听客户端事件,你可以使用 listenForWhisper 方法:

js
Echo.private(`chat.${roomId}`)
    .listenForWhisper('typing', (e) => {
        console.log(e.name);
    });

通知

通过将事件广播与通知结合使用,你的 JavaScript 应用程序可以在发生新通知时接收新通知,而无需刷新页面。在开始之前,请务必阅读使用广播通知频道的文档。

一旦你配置了一个通知使用广播频道,你就可以使用 Echo 的 notification 方法来监听广播事件。记住,频道名称应该与接收通知的实体的类名相匹配:

js
Echo.private(`App.Models.User.${userId}`)
    .notification((notification) => {
        console.log(notification.type);
    });

在这个例子中,所有通过 broadcast 频道发送给 App\Models\User 实例的通知都将由回调接收。App.Models.User.{id} 频道的频道授权回调包含在你应用程序的 routes/channels.php 文件中。