Broadcasting

Introduction

在许多现代 Web 应用程序中,WebSocket 用于实现实时、实时更新的用户界面。当服务器上的某些数据更新时,通常会通过 WebSocket 连接发送消息以供客户端处理。 WebSockets 提供了一种更有效的替代方法,可以持续轮询应用程序的服务器以获取应反映在 UI 中的数据更改。

例如,假设您的应用程序能够将用户数据导出到 CSV 文件并通过电子邮件发送给他们。但是,创建此 CSV 文件需要几分钟时间,因此您选择在排队的工作.当 CSV 创建并邮寄给用户时,我们可以使用事件广播来发送一个App\Events\UserDataExported 我们应用程序的 JavaScript 接收到的事件。收到事件后,我们可以向用户显示一条消息,告知他们的 CSV 已通过电子邮件发送给他们,而无需他们刷新页面。

为了帮助您构建这些类型的功能,Laravel 可以轻松地“广播”您的服务器端 Laravelevents 通过 WebSocket 连接。广播 Laravel 事件允许您在服务器端 Laravel 应用程序和客户端 JavaScript 应用程序之间共享相同的事件名称和数据。

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

支持的驱动程序

默认情况下,Laravel 包括两个服务器端广播驱动程序供您选择:推杆通道Ably.然而,社区驱动的包如laravel-websocketssoketi 提供不需要商业广播提供商的额外广播驱动程序。

Note
在深入研究事件广播之前,确保你已经阅读了 Laravel 的文档事件和听众.

服务器端安装

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

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

Configuration

您应用程序的所有事件广播配置都存储在config/broadcasting.php 配置文件。 Laravel 支持多种开箱即用的广播驱动程序:推杆通道,Redis, 和一个log 用于本地开发和调试的驱动程序。此外,一个null 包含的驱动程序允许您在测试期间完全禁用广播。这些驱动程序中的每一个都包含一个配置示例config/broadcasting.php 配置文件。

广播服务提供商

在广播任何事件之前,您首先需要注册App\Providers\BroadcastServiceProvider.在新的 Laravel 应用程序中,你只需要在providers 你的数组config/app.php 配置文件。这BroadcastServiceProvider 包含注册广播授权路由和回调所需的代码。

队列配置

您还需要配置并运行队列工作者.所有事件广播都是通过排队作业完成的,因此您的应用程序的响应时间不会受到正在广播的事件的严重影响。

推杆通道

如果您打算使用广播您的事件推杆通道,您应该使用 Composer 包管理器安装 Pusher Channels PHP SDK:

composer require pusher/pusher-php-server

接下来,您应该在config/broadcasting.php 配置文件。此文件中已包含一个 Pusher Channels 配置示例,允许您快速指定密钥、机密和应用程序 ID。通常,这些值应该通过PUSHER_APP_KEY,PUSHER_APP_SECRET, 和PUSHER_APP_ID 环境变量:

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

config/broadcasting.php 文件的pusher 配置还允许您指定额外的options 由 Channels 支持的,例如集群。

接下来,您需要将广播驱动程序更改为pusher 在你的.env 文件:

BROADCAST_DRIVER=pusher

最后,您就可以安装和配置了Laravel 回声,它将在客户端接收广播事件。

开源 Pusher 替代品

laravel-websocketssoketi 包为 Laravel 提供 Pusher 兼容的 WebSocket 服务器。这些包允许您在没有商业 WebSocket 提供商的情况下利用 Laravel 广播的全部功能。有关安装和使用这些软件包的更多信息,请参阅我们的文档开源替代品.

Ably

Note 下面的文档讨论了如何在“Pusher 兼容”模式下使用 Ably。但是,Ably 团队推荐并维护一个能够利用 Ably 提供的独特功能的广播公司和 Echo 客户端。有关使用 Ably 维护的驱动程序的更多信息,请查阅 Ably 的 Laravel 广播文档.

如果您打算使用广播您的事件Ably,您应该使用 Composer 包管理器安装 Ably PHP SDK:

composer require ably/ably-php

接下来,您应该在config/broadcasting.php 配置文件。此文件中已包含示例 Ably 配置,允许您快速指定密钥。通常,该值应通过ABLY_KEY 环境变量:

ABLY_KEY=your-ably-key

接下来,您需要将广播驱动程序更改为ably 在你的.env 文件:

BROADCAST_DRIVER=ably

最后,您就可以安装和配置了Laravel 回声,它将在客户端接收广播事件。

开源替代品

PHP

laravel-websockets package 是用于 Laravel 的纯 PHP,Pusher 兼容的 WebSocket 包。这个包允许您在没有商业 WebSocket 提供商的情况下利用 Laravel 广播的全部功能。有关安装和使用此软件包的更多信息,请参阅其官方文件.

Node

Soketi 是 Laravel 的基于节点的、与 Pusher 兼容的 WebSocket 服务器。在幕后,Soketi 利用 µWebSockets.js 实现极致的可扩展性和速度。这个包允许您在没有商业 WebSocket 提供商的情况下利用 Laravel 广播的全部功能。有关安装和使用此软件包的更多信息,请参阅其官方文件.

客户端安装

推杆通道

Laravel 回声 是一个 JavaScript 库,可以轻松订阅频道和监听服务器端广播驱动程序广播的事件。你可以通过 NPM 包管理器安装 Echo。在这个例子中,我们还将安装pusher-js 包,因为我们将使用 Pusher Channels 广播:

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

安装 Echo 后,您就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例。这样做的好地方是在底部resources/js/bootstrap.jsLaravel 框架中包含的文件。默认情况下,此文件中已包含示例 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
});

根据需要取消注释并调整 Echo 配置后,您可以编译应用程序的资产:

npm run dev

Note
要了解有关编译应用程序的 JavaScript 资产的更多信息,请参阅有关的文档Vite.

使用现有的客户端实例

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

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 团队推荐并维护一个能够利用 Ably 提供的独特功能的广播公司和 Echo 客户端。有关使用 Ably 维护的驱动程序的更多信息,请查阅 Ably 的 Laravel 广播文档.

Laravel 回声 是一个 JavaScript 库,可以轻松订阅频道和监听服务器端广播驱动程序广播的事件。你可以通过 NPM 包管理器安装 Echo。在这个例子中,我们还将安装pusher-js 包裹。

您可能想知道为什么我们要安装pusher-js JavaScript 库,即使我们使用 Ably 来广播我们的事件。值得庆幸的是,Ably 包括一个 Pusher 兼容模式,它让我们在客户端应用程序中监听事件时使用 Pusher 协议:

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

在继续之前,您应该在 Ably 应用程序设置中启用 Pusher 协议支持。您可以在 Ably 应用程序设置仪表板的“协议适配器设置”部分启用此功能。

安装 Echo 后,您就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例。这样做的好地方是在底部resources/js/bootstrap.js Laravel 框架中包含的文件。默认情况下,此文件中已包含示例 Echo 配置;但是,默认配置中bootstrap.js 文件适用于 Pusher。您可以复制以下配置以将您的配置转换为 Ably:

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 配置后,您可以编译应用程序的资产:

npm run dev

Note
要了解有关编译应用程序的 JavaScript 资产的更多信息,请参阅有关的文档Vite.

概念概述

Laravel 的事件广播允许您使用基于驱动程序的 WebSockets 方法将服务器端 Laravel 事件广播到客户端 JavaScript 应用程序。目前,Laravel 附带了推杆通道Ably 司机。这些事件可以很容易地在客户端使用Laravel 回声 JavaScript 包。

事件通过“频道”广播,可以指定为公共或私人。您的应用程序的任何访问者都可以在没有任何身份验证或授权的情况下订阅公共频道;但是,为了订阅私人频道,用户必须经过身份验证并获得授权才能收听该频道。

Note
如果您想探索 Pusher 的开源替代品,请查看开源替代品.

使用示例应用程序

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

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

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

ShouldBroadcast 界面

当用户查看他们的订单之一时,我们不希望他们必须刷新页面才能查看状态更新。相反,我们希望在应用程序创建时广播更新。所以,我们需要标记OrderShipmentStatusUpdated 事件与ShouldBroadcast界面。这将指示 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
{
    /**
     * The order instance.
     *
     * @var \App\Order
     */
    public $order;
}

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

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 反而:

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 channel 实际上是订单的创建者:

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 回声.首先,我们将使用private 订阅私人频道的方法。然后,我们可以使用listen 方法来听取OrderShipmentStatusUpdated 事件。默认情况下,事件的所有公共属性都将包含在广播事件中:

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

定义广播事件

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

ShouldBroadcast 接口要求您实现一个方法:broadcastOn.这broadcastOn 方法应返回事件应在其上广播的频道或频道数组。频道应该是实例Channel,PrivateChannel, 或者PresenceChannel.的实例Channel 代表任何用户都可以订阅的公共频道,而PrivateChannelsPresenceChannels 代表需要的私人频道渠道授权:

<?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 事件方法:

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

如果您使用自定义广播名称broadcastAs 方法,你应该确保用一个领先的注册你的听众. 特点。这将指示 Echo 不要将应用程序的命名空间添加到事件之前:

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

广播数据

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

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

但是,如果您希望对广播负载进行更细粒度的控制,您可以添加一个broadcastWith 方法到你的事件。此方法应返回您希望作为事件负载广播的数据数组:

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

广播队列

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

/**
 * 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 您的活动方法:

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

如果您想使用sync 队列而不是默认的队列驱动程序,你可以实现ShouldBroadcastNow界面而不是ShouldBroadcast:

<?php

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
    // ...
}

广播条件

有时您只想在给定条件为真时广播您的事件。您可以通过添加一个来定义这些条件broadcastWhen 方法到您的事件类:

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

广播和数据库交易

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

如果您的队列连接的after_commit 配置选项设置为false,您仍然可以通过定义一个$afterCommit 事件类的属性:

<?php

namespace App\Events;

use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

    public $afterCommit = true;
}

Note
要了解有关解决这些问题的更多信息,请查看有关的文档排队作业和数据库事务.

授权渠道

私人频道要求您授权当前经过身份验证的用户可以实际收听该频道。这是通过使用通道名称向 Laravel 应用程序发出 HTTP 请求并允许您的应用程序确定用户是否可以在该通道上收听来实现的。使用时Laravel 回声, 授权订阅私人频道的 HTTP 请求将自动发出;但是,您确实需要定义适当的路由来响应这些请求。

定义授权路由

值得庆幸的是,Laravel 可以轻松定义响应通道授权请求的路由。在里面App\Providers\BroadcastServiceProvider 包含在您的 Laravel 应用程序中,您将看到对Broadcast::routes 方法。此方法将注册/broadcasting/auth 处理授权请求的路由:

Broadcast::routes();

Broadcast::routes 方法会自动将其路由放在web 中间件组;但是,如果您想自定义分配的属性,您可以将一组路由属性传递给该方法:

Broadcast::routes($attributes);

自定义授权端点

默认情况下,Echo 将使用/broadcasting/auth 授权通道访问的端点。但是,您可以通过传递authEndpoint Echo 实例的配置选项:

window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    authEndpoint: '/custom/endpoint/auth'
});

自定义授权请求

您可以通过在初始化 Echo 时提供自定义授权方来自定义 Laravel Echo 执行授权请求的方式:

window.Echo = new Echo({
    // ...
    authorizer: (channel, options) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/api/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(null, response.data);
                })
                .catch(error => {
                    callback(error);
                });
            }
        };
    },
})

定义授权回调

接下来,我们需要定义实际确定当前经过身份验证的用户是否可以收听给定频道的逻辑。这是在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”部分是通配符。

授权回调模型绑定

就像 HTTP 路由一样,通道路由也可以利用隐式和显式路由模型绑定.例如,您可以请求实际的订单 ID,而不是接收字符串或数字订单 IDOrder 模型实例:

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 工匠命令。此命令将在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
{
    /**
     * 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 接口,您只需要使用事件的调度方法触发事件。事件调度程序会注意到事件被标记为ShouldBroadcast 接口并将事件排队以进行广播:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

仅对他人

在构建使用事件广播的应用程序时,您可能偶尔需要向除当前用户之外的给定频道的所有订阅者广播事件。您可以使用broadcast 帮手和toOthers 方法:

use App\Events\OrderShipmentStatusUpdated;

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

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

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

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

Warning
您的活动必须使用Illuminate\Broadcasting\InteractsWithSockets 特性,以便调用toOthers 方法。

Configuration

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

如果您不使用全局 Axios 实例,则需要手动配置您的 JavaScript 应用程序以发送X-Socket-ID 包含所有传出请求的标头。您可以使用以下方法检索套接字 IDEcho.socketId 方法:

var socketId = Echo.socketId();

自定义连接

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

use App\Events\OrderShipmentStatusUpdated;

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

或者,您可以通过调用broadcastVia 事件构造函数中的方法。但是,在这样做之前,您应该确保事件类使用InteractsWithBroadcasting 特征:

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

    /**
     * Create a new event instance.
     */
    public function __construct()
    {
        $this->broadcastVia('pusher');
    }
}

接收广播

监听事件

一旦你有安装并实例化 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')

离开频道

要离开频道,您可以拨打leaveChannel Echo 实例上的方法:

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

如果您想离开频道及其关联的私人和在线频道,您可以致电leave 方法:

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

Namespaces

您可能已经注意到在上面的示例中我们没有指定完整的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) => {
        // ...
    });

存在通道

存在通道建立在私有通道的安全性之上,同时公开了了解谁订阅了通道的附加功能。这使得构建强大的协作应用程序功能变得容易,例如在另一个用户正在查看同一页面或列出聊天室的居民时通知用户。

授权存在通道

所有存在频道也是私人频道;因此,用户必须有权访问它们.但是,在为存在通道定义授权回调时,您不会返回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 callback 会在频道加入成功后立即执行,并会收到一个数组,其中包含当前订阅该频道的所有其他用户的用户信息。这joining 方法会在新用户加入频道时执行,而leaving 方法会在用户离开频道时执行。这error 当身份验证端点返回 200 以外的 HTTP 状态代码或解析返回的 JSON 时出现问题时,将执行方法。

广播到现场频道

呈现频道可以像公共或私人频道一样接收事件。使用聊天室的例子,我们可能想要广播NewMessage 事件发送到房间的出席频道。为此,我们将返回一个实例PresenceChannel 从事件的broadcastOn 方法:

/**
 * Get the channels the event should broadcast on.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PresenceChannel('room.'.$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 模型状态变化定义自定义事件 并用ShouldBroadcast 界面。

但是,如果您在应用程序中没有将这些事件用于任何其他目的,那么创建仅用于广播它们的事件类可能会很麻烦。为了解决这个问题,Laravel 允许您指示 Eloquent 模型应该自动广播其状态更改。

首先,您的 Eloquent 模型应该使用Illuminate\Database\Eloquent\BroadcastsEvents 特征。此外,该模型应定义一个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;

    /**
     * Get the user that the post belongs to.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get the channels that model events should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
     */
    public function broadcastOn(string $event): array
    {
        return [$this, $this->user];
    }
}

一旦您的模型包含此特征并定义了它的广播频道,它将在创建、更新、删除、删除或恢复模型实例时开始自动广播事件。

此外,您可能已经注意到broadcastOn 方法接收一个字符串$event 争论。此参数包含模型上发生的事件类型,其值为created,updated,deleted,trashed, 或者restored.通过检查此变量的值,您可以确定模型应针对特定事件广播到哪些频道(如果有):

/**
 * Get the channels that model events should broadcast on.
 *
 * @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 如何创建底层模型广播事件。您可以通过定义一个newBroadcastableEvent Eloquent 模型上的方法。这个方法应该返回一个Illuminate\Database\Eloquent\BroadcastableModelEventOccurred 实例:

use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;

/**
 * Create a new broadcastable model event for the model.
 */
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
    return (new BroadcastableModelEventOccurred(
        $this, $event
    ))->dontBroadcastToCurrentUser();
}

示范广播公约

渠道约定

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

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

use Illuminate\Broadcasting\PrivateChannel;

/**
 * Get the channels that model events should broadcast on.
 *
 * @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 任何模型实例上的方法。例如,此方法返回字符串App.Models.User.1 为一个App\Models\User 模型与id1:

$user->broadcastChannel()

活动约定

由于模型广播事件与应用程序中的“实际”事件无关App\Events 目录,它们会根据约定分配一个名称和一个有效负载。 Laravel 的约定是使用模型的类名(不包括命名空间)和触发广播的模型事件的名称来广播事件。

因此,例如,对App\Models\Post 模型会将事件广播到您的客户端应用程序PostUpdated 具有以下有效载荷:

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

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

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

/**
 * The model event's broadcast name.
 */
public function broadcastAs(string $event): string|null
{
    return match ($event) {
        'created' => 'post.created',
        default => null,
    };
}

/**
 * Get the data to broadcast for the model.
 *
 * @return array<string, mixed>
 */
public function broadcastWith(string $event): array
{
    return match ($event) {
        'created' => ['title' => $this->title],
        default => ['model' => $this],
    };
}

收听模特广播

一旦你添加了BroadcastsEvents 模型的特征并定义了模型的broadcastOn 方法之后,您就可以开始在客户端应用程序中侦听广播的模型事件了。在开始之前,您可能希望查阅完整的文档监听事件.

首先,使用private 方法来检索通道的实例,然后调用listen 监听指定事件的方法。通常,给的频道名称private 方法应该对应于 Laravel 的示范广播公约.

获得通道实例后,您可以使用listen 监听特定事件的方法。由于模型广播事件与应用程序中的“实际”事件无关App\Events 目录,事件名称 必须以a为前缀. 表明它不属于特定的命名空间。每个模型广播事件都有一个model 包含模型所有可广播属性的属性:

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

客户活动

Note
使用时推杆通道,您必须在您的“应用程序设置”部分启用“客户端事件”选项应用程序仪表板 为了发送客户端事件。

有时您可能希望在不访问 Laravel 应用程序的情况下向其他连接的客户端广播事件。这对于诸如“键入”通知之类的事情特别有用,在这种情况下,您希望提醒应用程序的用户另一个用户正在给定屏幕上键入消息。

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

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

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

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

Notifications

通过将事件广播与notifications,您的 JavaScript 应用程序可能会在新通知出现时收到通知,而无需刷新页面。在开始之前,请务必阅读有关使用的文档广播通知频道.

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

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

在此示例中,所有发送到的通知App\Models\User 实例通过broadcast channel 将被回调接收。的通道授权回调App.Models.User.{id} 默认包含通道BroadcastServiceProvider 随 Laravel 框架一起提供。

豫ICP备18041297号-2