广播系统
广播系统
简介
在现代的 web 应用程序中, WebSockets 被用来实现实时、即时更新用户接口。 当服务器上的数据更新后,更新信息会通过 WebSocket 连接发送到客户端等待处理。为了在UI中展示出这些数据的变化相比于不停地轮询应用程序 , WebSockets 是一种更加可靠和高效的选择。
举一个例子, 假设在应用程序中能够导出用户的 CSV 数据并且发送给他们。可是创建 CSV 文件要花费很长时间,因此你选择使用 队列任务 去创建文件和发送邮件。当创建了 CSV 文件并将其发送给用户后, 我们能够创建使用一个广播事件比如 App\Events\UserDataExported
,然后在应用中利用 JavaScript 来接收这个事件。一旦接收到事件,我们就可以向用户显示一条消息,表明他们的 CSV 已经通过电子邮件发送给他们,而不需要他们刷新页面。
为了帮助构建这些类型的功能, Laravel 通过WebSocket连接使它很容易的去「广播」您的服务端Laravel 事件 。 广播Laravel事件可让您在服务器端Laravel应用程序和客户端JavaScript应用程序之间共享相同的事件名称和数据。
支持的驱动
默认 Laravel 提供两个服务端广播驱动供你选择:Pusher Channels 和 Ably。 不管怎样, 社区驱动包如 laravel-websockets 提供不需要商业广播提供商的其他广播驱动程序。
技巧:在进入事件广播之前,请确保您已阅读Laravel的文档,关于 事件和监听。
服务端安装
要开始使用Laravel的事件广播,我们需要在Laravel应用程序中进行一些配置并安装一些软件包。
事件广播由服务器端广播驱动程序完成,该驱动程序广播您的Laravel事件,以便Laravel Echo(一个JavaScript库)可以在浏览器客户端中接收它们。不用担心-我们将逐步完成安装过程的每个部分。
配置
您应用程序的所有事件广播配置都存储在 config/broadcasting.php
配置文件中。 Laravel开箱即用地支持多种广播驱动程序:Pusher Channels,Redis,和本地的 log
调试和开发驱动。 另外,还包含一个 null
驱动程序,您可以在调试期间完全禁用广播。 在配置文件config/broadcasting.php
中为每个驱动程序提供了一个配置示例。
广播服务提供者
在广播任何事件之前,你首先需要注册 App\Providers\BroadcastServiceProvider
。在新的 Laravel 应用程序中,你只需要在配置文件的 providers
数组中取消注释该提供程序 config/app.php
。BroadcastServiceProvider
包含注册广播授权路由和回调所必需的代码。
队列配置
你还需要配置和运行队列工作器。所有事件广播都是通过排队的作业完成的,因此应用程序的响应时间不会受到广播事件的严重影响。
推送通道
如果你打算使用 推送通道广播事件,则应该使用 Composer 软件包管理器安装推送通道 PHP SDK:
composer require pusher/pusher-php-server "~4.0"
接下来,你应该在 config/broadcasting.php
配置文件中配置你的推送通道凭据。此文件中已经包含示例推送通道配置,使你可以快速指定密钥,机密和应用程序 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
通道支持的其他功能,例如群集。
接下来,你需要将你的广播驱动程序更改为 pusher
在你的 .env
文件中:
BROADCAST_DRIVER=pusher
最后,你准备配置Laravel Echo,它将在客户端接收广播事件。
Pusher兼容Laravel Websocket
laravel-websockets包是一个纯 PHP, Pusher 兼容的 WebSocket 包的Laravel。这个包允许你在没有商业 WebSocket 提供商的情况下充分利用 Laravel 广播的功能。有关安装和使用这个包的更多信息,请参阅它的官方文档。
Ably
如果计划使用 Ably 广播事件,则应使用 Composer 软件包管理器安装 Ably PHP SDK:
composer require ably/ably-php
接下来,你应该在 config/broadcasting.php
配置文件中配置 Ably 凭据。此文件中已经包含一个示例 Ably 配置,使你可以快速指定密钥。通常,此值应通过 ABLY_KEY
环境变量设置:
ABLY_KEY=your-ably-key
接下来,你需要将你的广播驱动程序更改为 ably
在您的 .env
文件中:
BROADCAST_DRIVER=ably
最后,您准备安装和配置Laravel Echo,它将在客户端接收广播事件。
开源替代品
laravel-websockets 包是一个纯 PHP, Pusher 兼容的 WebSocket 包的Laravel。这个包允许你在没有商业 WebSocket 提供商的情况下充分利用 Laravel 广播的功能。有关安装和使用这个包的更多信息,请参阅它的官方文档。
客户端安装
推送通道
Laravel Echo 是一个 JavaScript 库,可以轻松地订阅频道和侦听服务器端广播驱动程序广播的事件。你可以通过 NPM 包管理器安装 Echo。在本例中,我们还将安装 Pusher -js
包,因为我们将使用 Pusher channel 广播:
npm install --save-dev laravel-echo pusher-js
一旦安装了 Echo,就可以在应用程序的 JavaScript 中创建一个新的 Echo 实例。一个不错的选择是在resources/js/bootstrap.js
框架随附的文件的底部。默认情况下,示例Echo配置已包含在此文件中你只需要取消注释即可:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
一旦取消注释并根据需要调整了 Echo 配置,就可以编译应用程序的资产:
npm run dev
技巧:要了解更多关于编译你的应用的 JavaScript 资产,请参考[Laravel Mix](/docs/ Laravel /8.x/ Mix)的文档。
使用现有的客户端实例
如果你已经具有要使用 Echo 的预配置 Pusher Channels 客户端实例,则可以通过 client
配置选项将其传递给Echo :
import Echo from 'laravel-echo';
const client = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-channels-key',
client: client
});
Ably
Laravel Echo 是一个通过服务端广播驱动无痛订阅频道和监听事件广播的 JavaScript 库。 你可以通过 NPM 安装 Echo ,本例里,我们也安装了 pusher-js
包。
你可能会想,我们正在使用 Ably 广播事件,为什么会安装这个 pusher-js
JavaScript 库。 因为 Ably 包含了一个兼容 Pusher 的模式,它允许我们在监听客户端程序的事件时,使用 Pusher 协议。
npm install --save-dev laravel-echo pusher-js
*继续之前,你要确保 Pusher 协议支持你的 Ably 程序设置。确保这个功能在 Ably 应用设置面板的「协议适配器设定」选项中已被启用。 *
一旦 Echo 安装了,你就可以在 JavaScript 脚本里创建一个新的 Echo 实例。在 Laravel 框架的 resources/js/bootstrap.js
文件的下方,运行这个脚本非常合适。默认下,Echo 配置范例已经囊括在内了;然而,bootstrap.js
文件中默认配置的是 Pusher 。因此你可以拷贝下面的配置到你的
Ably 中去:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443,
disableStats: true,
encrypted: true,
});
注意:我们的 Ably Echo 配置引用了一个 MIX_ABLY_PUBLIC_KEY
环境变量。这个变量的值应该是 Ably 的公钥。这个公钥是 Ably 的 key 的一部分。
一旦你已按需调整好 Echo 配置后,你就可以编译程序资源了:
npm run dev
技巧:学习更多有关编译 JavaScript 资源的内容, 请查看文档 Laravel Mix。
概念综述
Laravel 的事件广播允许你使用基于驱动的 WebSockets 将服务端的 Laravel 事件广播到客户端的 JavaScript 应用程序。 目前,Laravel 自带了 Pusher Channels 和 Ably 驱动。通过使用 Laravel Echo JavaScript 包,我们可以轻松地在客户端消费事件。
事件通过「 频道 」来广播,这些频道可以被设定为公开或私有。任何访客都可以不经授权或认证订阅一个公开频道;然而,如果想要订阅一个私有频道,那么该用户必须通过认证,并获得该频道的授权。
技巧:如果你想使用开源的基于 PHP 的 Pusher 替代方案, 请查看 laravel-websockets 包。
使用示例程序
深入了解事件广播的每个组件之前,让我们先用一个电商网站高度概括下。
在我们的程序里, 我们假设有一个允许用户查看订单配送状态的页面。我们也假设有一个 OrderShipmentStatusUpdated
事件会在配送状态更新时被程序触发:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);
<code>ShouldBroadcast</code> 接口
当用户查看一个自己的订单时,我们不希望他们必须通过刷新页面才能看到状态更新。相反,我们希望一旦有程序更新时就广播给客户端。所以,我们需要标记实现了 ShouldBroadcast
接口的OrderShipmentStatusUpdated
事件。Laravel 会在事件被触发时广播该事件:
<?php
namespace App\Events;
use App\Order;
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 OrderShipmentStatusUpdated implements ShouldBroadcast
{
/**
* 订单实例。
*
* @var \App\Order
*/
public $order;
}
ShouldBroadcast
接口需要事件定义一个 broadcastOn
方法。该方法负责返回需要广播事件的频道。这个方法的空模板已经被预定义好了,所以我们只需要填充其它细节。我们只想要订单的创建者才能看到状态的更新,所以我们把这个事件广播到与此订单相关的私有频道上去:
/**
* 获取事件应广播的频道
*
* @return \Illuminate\Broadcasting\PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('orders.'.$this->order->id);
}
授权频道
记住,只有授权用户才能监听私有频道。我们可以在程序的 routes/channels.php
文件里, 定义频道的授权规则。本例中,我们需要去验证任何试图监听 order.1
私有频道的用户,是否是订单实际上的创建者:
use App\Models\Order;
Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
channel
方法接收两个参数:频道名和一个返回 true
或 false
来表示用户是否有权监听该频道的回调函数。
所有授权回调都接收已鉴权用户作为其第一个参数,并将其他通配符参数作为其后续参数。本例中,我们用 {orderId}
占位符来通配表示频道「ID」。
监听事件广播
接下来,剩余的工作就是在我们的 JavaScript 程序中监听事件。我们使用 Laravel Echo 做这件事。首先, 我们使用 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
的实例代表任何用户可以订阅的公共频道,然而 PrivateChannels
和 PresenceChannels
代表需要 频道授权 的私有频道:
<?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;
/**
* 创建服务的用户。
*
* @var \App\Models\User
*/
public $user;
/**
* 新建一个新的事件实例。
*
* @param \App\Models\User $user
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* 获取事件应广播的频道。
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'.$this->user->id);
}
}
实现 ShouldBroadcast
接口后,你仅须按你所需 触发事件 。一旦事件被触发了, 队列任务 将自动地通过指定的广播驱动程序广播该事件。
广播名称
默认下,Laravel 将通过事件类的名称广播该事件,但是,你也可以通过在事件中定义一个 broadcastAs
方法自定义事件的名称:
/**
* 事件的广播名称
*
* @return string
*/
public function broadcastAs()
{
return 'server.created';
}
如果你使用 broadcastAs
方法自定义广播名称,你要确保注册的事件名有一个前导的 .
字符。 这个会告诉 Echo 不要将程序的命名空间添加到事件中:
.listen('.server.created', function (e) {
....
});
广播数据
当一个事件被广播,它的所有 public
属性都会被自动序列化并作为事件有效载荷广播,同时允许你从 JavaScript 应用程序访问它的任何公共数据。因此,举例来说:如果你的事件有一个包含 Eloquent 模型的公共属性 $user
,这个事件的广播有效载荷应该是:
{
"user": {
"id": 1,
"name": "Patrick Stewart"
...
}
}
然而,如果你期望对广播有效载荷有更细粒度的操控,你可以添加一个 broadcastWith
到事件中, 这个方法返回一个数据数组作为广播事件的有效载荷:
/**
*获得广播数据
*
* @return array
*/
public function broadcastWith()
{
return ['id' => $this->user->id];
}
广播队列
默认下,在 queue.php
配置文件里,每个广播事件都放置在默认队列中,并且使用默认连接。你可以在事件类中通过定义 connection
和 queue
属性自定义队列连接和名称。
/**
* 广播事件时使用的队列连接名称
*
* @var string
*/
public $connection = 'redis';
/**
* 放置广播任务的队列名称
*
* @var string
*/
public $queue = 'default';
如果你想用 sync
队列替代默认的队列驱动来广播,你可以实现 ShouldBroadcastNow
接口替代 ShouldBroadcast
:
<?php
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
//
}
广播条件
有时,你仅仅想在给定条件为真时才广播事件,你可以通过在事件类里添加一个 broadcastWhen
方法定义这些条件。
/**
* 判断是否应该广播事件
*
* @return bool
*/
public function broadcastWhen()
{
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;
}
技巧:了解更多此问题的替代方案,请阅览关于 队列任务和数据库事务 的文档。
授权频道
私有频道需要你授权给已鉴权的用户才可以实际地监听此频道。它通过发送一个带有频道名称的 HTTP 请求到你的 Laravel 程序实现,并允许你的程序判断用户是否可以监听该频道。使用 Laravel Echo 时, 私有频道授权订阅的 HTTP 请求将自动进行。但是,你需要定义响应这些请求的正确路由。
定义授权路由
幸好,Laravel 可以轻松定义路由,来响应频道授权的请求。 在 Laravel 自带的 App\Providers\BroadcastServiceProvider
中,你会看到一个 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'
});
定义授权回调
接下来,我们需要定义判断当前已鉴权用户是否可以监听给定频道的业务逻辑。它在你的程序附带的 routes/channels.php
文件中完成 。在此文件里你可以使用 Broadcast::channel
方法注册频道授权回调:
Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
channel
方法接收两个参数:频道名称和一个返回 true
或 false
来指示用户是否有权在频道上监听的回调函数。
所有授权回调都接收已鉴权用户作为其第一个参数,并将其他通配符参数作为其后续参数。本例中,我们用 {orderId} 占位符来通配表示频道「ID」部分。
授权模型回调绑定
就像 HTTP 路由一样,频道路由也可以利用隐式和显式路由模型绑定 路由模型绑定 。例如:不使用接收一个字符串或者数字订单 ID 的方式,你也可以请求一个实际的 Order
模型实例:
use App\Models\Order;
Broadcast::channel('orders.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});
注意:不像 HTTP 路由模型绑定,频道模型绑定不支持自动的 隐式模型绑定作用域 。 然而这不是问题,因为大多数的频道都可以被一个基于单一模型的唯一值或者主键所限定。
授权回调验证
私有和 Presence 广播频道通过程序默认的认证看守器来认证当前用户。如果用户未经过认证,频道授权则会被自动拒绝,并且授权回调永远不会执行。 然而,你可以分配多个自定义守卫,以便有需求时认证进来的请求:
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
{
/**
* 新建一个新的频道实例
*
* @return void
*/
public function __construct()
{
//
}
/**
* 验证用户对频道的访问权限。
*
* @param \App\Models\User $user
* @param \App\Models\Order $order
* @return array|bool
*/
public function join(User $user, Order $order)
{
return $user->id === $order->user_id;
}
}
技巧:和很多 Laravel 中其他类一样,频道类会被 服务容器 自动解析。 所以你可以在构造函数中根据类型提示输入频道所需的任何依赖。
广播事件
一旦你定义了一个事件并用 ShouldBroadcast
接口标记了它,你仅需要使用事件的调度方法触发它。事件调度器会注意到这个被 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
方法告诉广播程序不向当前用户广播该事件。
注意:你的事件必须使用
Illuminate\Broadcasting\InteractsWithSockets
trait 才能调用toOthers
方法。
配置
当初始化 Laravel Echo 实例时,连接会被分配一个套接字 ID。如果你在 JavaScript 程序里使用全局 Axios 实例发起 HTTP 请求,这个套接字 ID 将自动作为 X-Socket-ID
标题头附加到每个发出的请求中。然后,当调用 toOthers
方式时,Laravel 会从标题头提取套接字 ID 并且指示广播系统不给持有这个套接字 ID 的连接广播。
如果你没使用全局 Axios 实例,那么需要你手动地配置 JavaScript 程序使之发出请求时附带着 X-Socket-ID
标题头。可以使用 Echo.socketId
方法获得这个套接字 ID:
var socketId = Echo.socketId();
接收广播
监听事件
一旦你已经 安装并实例化了 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(...);
退出频道
你可以在 Echo 实例中调用 leaveChannel
方法退出频道:
Echo.leaveChannel(`orders.${this.order.id}`);
如果你想退出一个频道以及相关的私有和 Presence 频道,你可以调用 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) => {
//
});
Presence 频道
Presence 频道建立在私有频道安全性的基础上,同时对外暴露出谁订阅了频道的附加特性。 这样可以轻松地构建功能强大的协作程序,例如:通知用户有其他用户在查看相同页面或聊天室的有其他用户。
授权 Presence 频道
所有在线频道也都是私有频道;因此,用户必须 授权访问它们 。但是,在为 Presence 频道定义授权回调时,如果用户有权加入该频道,则不会返回 true
。 相反,你应该返回此用户的数据数组。
你的JavaScript 程序的 Presence 频道事件侦听器可使用授权回调返回的数据。如果用户未被授权加入 Presence 频道,则应返回false
或 null
:
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});
加入 Presence 频道
你可以使用 Echo 的 join
方法加入 Presence 频道。join
方法将返回一个 PresenceChannel
的实现类,它跟着 listen
方法一起展示,允许你订阅 here
, joining
和 leaving
事件。
Echo.join(`chat.${roomId}`)
.here((users) => {
//
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
});
一旦成功加入频道,将立即执行 here
回调,并且将接收包含当前订阅该频道的所有其他用户的用户信息的数组。 当新用户加入频道时,将执行 joining
方法,而当用户退出频道时,将执行 leaving
方法。
广播到 Presence 频道
Presence 频道可以像公共或私有频道一样接收事件。 使用聊天室举例,我们可能想将 NewMessage
事件广播到房间的 Presence 频道。我们从事件的 broadcastOn
方法返回一个 PresenceChannel
实例实现它:
/**
* 获取可以广播事件的频道
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('room.'.$this->message->room_id);
}
与其他事件一样,你可以使用 broadcast
助手函数和 toOthers
方法排除当前用户接收广播:
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();
作为其他类型事件的例子,你可以通过 Echo 的 listen
方法监听发送到 Presence 频道的事件:
Echo.join(`chat.${roomId}`)
.here(...)
.joining(...)
.leaving(...)
.listen('NewMessage', (e) => {
//
});
客户端事件
技巧:使用 Pusher 频道 时,必须在 应用仪表盘 的「 应用设置 」部分启用「 客户端事件 」选项以便发送客户端事件。
有时,你可能希望不使用 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);
});
消息通知
通过将事件广播与 通知 配对,你的 JavaScript 程序可以在页面无刷新下接收通知。开始前,请务必阅读有关使用 广播通知频道 的文档。
一旦你配置完通知,准备使用广播频道, 你可以使用 Echo notification
方法监听广播事件。 记住,频道名应匹配接受通知的类名:
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});
在此例中,所有通过 broadcast
频道发送到 App\Models\User
实例的通知都通过回调的形式接受。App.Models.User.{id}
频道的频道授权回调包含在 Laravel 框架默认附带的 BroadcastServiceProvider
中。