搜索
首页php框架LaravelLaravel框架内置的Broadcast功能如何实现与客户端实时通信

Laravel框架集成众多开发包的而功能, 虽然它的东西很多,但是它确是一个很好的框架。接下来的这篇文章将基于 Laravel 5.6 版本为大家讲述如何使用内置的 Broadcast(广播)功能实现与客户端实时通信。

1、准备

广播系统

用户认证

事件系统

队列系统

前端指南

tlaverdure/laravel-echo-server

没错,这是你需要的知识储备。

因为 PHP 本身并不支持 WebSocket,所以我们需要一个能够将「服务器」数据发给「客户端」的间接层。也就是说,实现实时通信可以大致分为两个步骤:

「Laravel」-> 「间接层」

「间接层」->(via WebSocket)->「客户端」

至于间接层我们采用什么实现,后面再讲。

2、配置

根据如上广播系统的文档,我们首先需要做如下的配置工作。

(1)首先,修改 config/broadcasting.php 或 .env 文件。确保 Broadcast Default Driver 是 log,以打开此功能,且便于我们调试。

(2)使用 Broadcast 广播,必须了解 Laravel 的事件系统,它们是互相依赖的。接下来我们创建一个可以「被广播」的事件。

修改app/Providers/EventServiceProvider.php,在成员变量$listen内追加:

'App\Events\OrderShipped' => [
    'App\Listeners\SendShipmentNotification',
],

这里我们将此事件命名为 OrderShipped(订单已结算);执行 php artisan event:generate 生成事件类及其监听器。

若是需要将事件执行(即广播到客户端)修改为异步,请参考如上队列系统文档。

(3)为了能让事件「被广播」,我们需要让事件类继承 ShouldBroadcast 接口。

打开 app/Events/OrderShipped.php,修改类定义为:

class OrderShipped implements ShouldBroadcast

(4)ShouldBroadcast 接口要求实现 broadcastOn 方法,用于告知框架:此事件应该被发送到哪个「频道」。

Laravel 的广播系统允许有多个频道存在,你可以使用用户名区别不同频道,这样不同的用户手痛不同频道,即可获得不同消息,也就能实现和不同客户端进行单独通信。

当然,你也可以任意命名频道,但最好具有有一定规则。

因为我们刚刚使用 Artisan 命令生成的事件代码,所以在文件最下方,你已经能够看到 broadcastOn 方法的定义了。我们稍作修改:

public function broadcastOn()
{
    return new Channel('orderStatus');
}

这里我们将频道命名为:orderStatus,并返回。也就是说此事件被广播时,它将会被广播到名字为 orderStatus 的频道。

这是一个「公有频道」,任何人可以监听此频道,并收到广播的消息。Laravel 同时提供了「私有频道」,经过权限验证后才能成功监听。我们后面再讲。

(5)默认情况下,Laravel 会将「事件名」作为广播的「消息名」,且不带任何数据。我们可以在事件类内添加任意成员变量,并修改构造函数,以实现将数据发送给客户端。

//可添加任意成员变量
public $id;
//事件构造函数
public function __construct($id)
{
    $this->id = $id;
}
//自定义广播的消息名
public function broadcastAs()
{
    return 'anyName';
}

(6)如上,我们已经基本建立起广播的基本机制。接下来我们需要一个能「触发事件」(即发送广播)的接口。

在 routes/api.php 添加如下代码:

Route::get('/ship', function (Request $request)
{
    $id = $request->input('id');
    event(new OrderShipped($id)); // 触发事件
    return Response::make('Order Shipped!');
});

(7)好了!打开 Postman,输入:http://***/api/ship?id=1000,发送。

打开 storage/logs/laravel.log,你会发现多了几行:

[2018-03-02 01:41:19] local.INFO: Broadcasting [App\Events\OrderShipped] on channels [orderStatus] with payload:
{
    "id": "1000",
    "socket": null
}

恭喜,你已经成功地配置好 Broadcast 的 log Driver。

3、广播

在上一节,我们采用 log 作为 Broadcast Driver,也就是说广播的消息会被记录到日志内,那么如何真正地与客户端进行通信呢?这就需要用到最开始提到的「间接层」了。

(1)首先,将 Driver 由 log 修改为 pusher。

为了节省安装 Redis 的步骤,我们将采用 HTTP 协议直推至兼容的「本地 Pusher 服务器」(即间接层)。

(2)由于 Laravel 内置并没有携带 Broadcast Pusher Driver,因此需要使用 Composer 安装 Pusher PHP SDK:

composer require pusher/pusher-php-server

(3)注册 App\Providers\BroadcastServiceProvider。

对于 Laravel 5.6,只需要取消 config/app.php 内 providers 数组中的对应注释即可。

(4)接下来,需要安装并配置服务器与客户端通信的「间接层」。

我们采用官方文档推荐的:tlaverdure/laravel-echo-server。这是一个使用 Node.js + Socket.IO 实现的 WebSocket 服务端。

它兼容 Pusher HTTP API,所以如上能够直接将 Driver 修改为 Pusher,而不是 Redis。

npm install -g laravel-echo-server

初始化配置文件,按照提示填写即可。

laravel-echo-server init

打开 laravel-echo-server.json,检查部分关键配置项是否正确:

"authHost": "http://xxx" // 确保能够访问到你的 Laravel 项目
"port": "6001" // 建议不作修改,这是与客户端通信的端口
"protocol": "http" // 与客户端通信的协议,支持 HTTPS

复制两个值:clients.appId 以及 clients.key,并修改 config/broadcasting.php。

'pusher' => [
    'driver' => 'pusher',
    'key' => env('PUSHER_APP_KEY'),
    'secret' => null,
    'app_id' => env('PUSHER_APP_ID'),
    'options' => [
        'host' => 'localhost',
        'port' => 6001,
    ],
],

顾名思义,将 appId 和 key 分别填入相应配置项或修改 .env 文件即可。

接下来,我们便可以使用命令 laravel-echo-server start 来启动服务器,监听来自 Laravel 的「广播」请求、以及来自客户端的「收听」请求,并转发相应广播消息。

(5)从这里开始我们将会配置前端部分。

首先,需要配置 CSRF Token。

如果你使用 Blade 模板引擎,则执行 php artisan make:auth 命令即可将 Token 加入 resources/views/layouts/app.blade.php。

若没有使用此模板文件,则可以直接在 Blade 模板文件首行直接写入 Meta 值。

为了便于测试,我们在 resources/views/welcome.blade.php 内添加:

<meta name="csrf-token" content="{{ csrf_token() }}">

对于前后端分离的项目,可关闭 CSRF Token 验证。

(6)其次,你需要引用 Socket.IO 的客户端 JS 文件,位置同上。

<script src="//{{ Request::getHost() }}:6001/socket.io/socket.io.js"></script>

(7)这里我们采用官方的 Laravel Echo 扩展包收听服务端广播。打开 resources/assets/js/bootstrap.js,修改最后几行即可。

import Echo from 'laravel-echo'

window.Echo = new Echo({
    broadcaster: &#39;socket.io&#39;,
    host: window.location.hostname + &#39;:6001&#39;
});

接着编写「收听频道」代码,非常简单:

Echo.channel(`orderStatus`) // 广播频道名称
    .listen(&#39;OrderShipped&#39;, (e) => { // 消息名称
        console.log(e); // 收到消息进行的操作,参数 e 为所携带的数据
    });

(8)安装依赖,编译前端文件。执行如下命令:

npm install
npm run dev

最后,在 Blade 模板内引用我们刚刚写好的 JS 脚本。由于 app.js 默认已经引用 bootstrap.js,所以我们只需要引用 app.js 即可。

我们在第(5)步的文件内添加:

<script src="{{ asset(&#39;/js/app.js&#39;) }}"></script>

(9)好了!在查看效果前,不要忘记执行第(4)步的最后一条命令,启动 Laravel Echo Server。

Laravel 默认已经定义首页路由渲染 welcome.blade.php 模板,现在只要使用浏览器访问应用 URL 即可。

如果查看 Chrome 控制台,没有任何错误产生;查看命令行窗口,没有错误输出;则说明客户端与服务器似乎已经正常建立 WebSocket 连接。

这时,你可以重新打开Postman,发送上一节中的请求。

再次查看如上两个窗口,会有惊喜哟。

4、私有频道

上一节我们成功实现可以被任何人收听的「共有频道」广播,那么如何与部分客户端进行通讯呢?仅仅依靠前端的验证是不够的。我们需要创建带有「认证」功能的「私有频道」。

(1)首先,打开 app/Providers/BroadcastServiceProvider.php,在上一节中我们已经注册此服务提供者,现在我们需要取消注释一部分代码。

public function boot()
{
    Broadcast::routes(); // 还记得 laravel-echo-server.json 的 authEndpoint 配置项吗?
    require base_path(&#39;routes/channels.php&#39;);
}

Broadcast::routes() 用于注册验证路由(即 /broadcasting/auth),当客户端收听频道时,Laravel Echo Server 会访问此路由,以验证客户端是否符合「认证」条件。

(2)Broadcast 认证分为两个部分:

使用 Laravel 内置的 Auth 系统进行认证。

根据自定义规则进行部分频道的认证。

(3)首先,需要配置 Auth 认证系统。

根据情况修改 .env 文件的数据库配置项后,只需要执行 php artisan make:auth 创建所需文件,再执行 php artisan migrate 创建所需数据库结构即可。

深入了解,请参考用户认证文档。

接下来我们在浏览器中打开你的应用,会发现右上角多了登录和注册,我们随意注册一个测试用户以备使用。

(4)接下来,配置频道认证。

还记得第(1)步的 routes/channels.php 吗,我们打开此文件。并新增一条频道认证规则。

注意:虽然此文件位于 routes 目录下,但并不是路由文件!在此定义后并不能访问,且无法使用分组、中间件。所有的验证路由都已经在 Broadcast::routes() 中定义。

Broadcast::channel(&#39;orderStatus&#39;, function ($user, $value) {
    return true; // or false
});

由于 Broadcast 已经使用 Auth 进行用户登录认证,所以我们只需无条件返回 true 即可实现:任何已登录用户都可以收听此频道。

(5)认证部分我们已经配置完成,接下来将共有频道的定义改为私有。

修改广播消息基于的事件类 app/Events/OrderShipped.php:

public function broadcastOn()
{
    return new PrivateChannel(&#39;orderStatus&#39;); // 私有频道
}

修改客户端收听代码 resources/assets/js/bootstrap.js。

Echo.private(`orderStatus`) // 私有频道
    .listen(&#39;OrderShipped&#39;, (e) => {
        console.log(e);
    });

(6)接下来,再次运行 Laravel Echo Server。使用浏览器打开你的应用首页,在未登录状态,可以看到 Echo Server 输出一个来自 Laravel 的 AccessDeniedHttpException 异常,提示用户认证失败,无法收听频道。

登录后,即可获得与上一节相同的预期结果。

(7)如上,我们成功实现所有登录用户均可收听私有频道。那么如何实现某部分用户可以收听,某部分用户不可以收听频道?例如:某个用户均有属于自己的频道,他只能收听自己的频道。请继续往下看。

首先,修改广播消息基于的事件类 app/Events/OrderShipped.php。你需要将频道命名修改为动态的值。

public $userId; // 新增成员变量 userId,不要忘记在构造函数内对其进行赋值

public function broadcastOn()
{
    return new PrivateChannel(&#39;orderStatus-&#39; . $this->userId); // 动态命名私有频道
}

其次,修改第(4)步中的 routes/channels.php 文件。Broadcast 支持使用通配符匹配「某一类」频道进行验证。

Broadcast::channel(&#39;orderStatus-{userId}&#39;, function ($user, $value) {
    // $user    Auth认证通过的用户模型实例
    // $value   频道规则匹配到的 userId 值
    return $user->id == $value; // 可使用任意条件验证此用户是否可监听此频道
});

最后别忘记修改前端收听的频道名称。

再次打开浏览器测试即可发现:在本例中,若客户端收听的频道不匹配当前用户 ID,则会报错。

(8)如上,我们成功实现对私有频道进行自定义规则的认证;但如果我们没有使用 Auth 认证系统,或采用了自己编写的用户认证中间件,该如何兼容呢?

经过一番源码调试,我发现 Broadcast 在 vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/ 文件夹下定义的 Broadcaster 内调用 $request->user() 进行了用户验证。

例如我们采用的 PusherBroadcaster.php:

/**
 * Authenticate the incoming request for a given channel.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return mixed
 * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
 */
public function auth($request)
{
    if (Str::startsWith($request->channel_name, [&#39;private-&#39;, &#39;presence-&#39;]) &&
        ! $request->user()) {
        throw new AccessDeniedHttpException;
    }
    $channelName = Str::startsWith($request->channel_name, &#39;private-&#39;)
                        ? Str::replaceFirst(&#39;private-&#39;, &#39;&#39;, $request->channel_name)
                        : Str::replaceFirst(&#39;presence-&#39;, &#39;&#39;, $request->channel_name);
    return parent::verifyUserCanAccessChannel(
        $request, $channelName
    );
}

由此可得,我们有两种方式实现。

第一种

直接注释 throw new AccessDeniedHttpException,并修改 app/Providers/BroadcastServiceProvider.php。

Broadcast::routes() 可接收一个参数。在 vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php 可查看其定义:

/**
 * Register the routes for handling broadcast authentication and sockets.
 *
 * @param  array|null  $attributes
 * @return void
 */
public function routes(array $attributes = null)
{
    if ($this->app->routesAreCached()) {
        return;
    }
    $attributes = $attributes ?: [&#39;middleware&#39; => [&#39;web&#39;]];
    $this->app[&#39;router&#39;]->group($attributes, function ($router) {
        $router->post(&#39;/broadcasting/auth&#39;, &#39;\\&#39;.BroadcastController::class.&#39;@authenticate&#39;);
    });
}

通过源码可知:此参数等效于 Route::group() 的第一个参数。所以我们只要将其修改为如下形式:

Broadcast::routes([&#39;middleware&#39; => [&#39;yourMiddleware&#39;])

并在中间件内进行用户认证;如未登录,照常抛出 AccessDeniedHttpException 异常即可。

第二种

在 vendor/laravel/framework/src/Illuminate/Http/Request.php 可以查看到 $request->user() 的定义。

/**
 * Get the user making the request.
 *
 * @param  string|null  $guard
 * @return mixed
 */
public function user($guard = null)
{
    return call_user_func($this->getUserResolver(), $guard);
}

如上可知,它使用 $this->userResolver 内的匿名函数获取用户模型。所以我们只需要在AuthServiceProvider 注册后,Broadcast 认证前,替换掉其 userResolver 即可。

例如:继承 Illuminate\Auth\AuthServiceProvider(vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php),并重写 registerRequestRebindHandler 方法及构造函数,添加如下代码。

$request->setUserResolver(function ($guard = null) use ($app) {
    // 在此判断用户登录状态
    // 若登录,请返回 App\User 或其它用户模型实例
    // 未登录,请返回 null
});

修改 config/app.php,使用改造过的 AuthServiceProvider 类替换原服务提供者即可。

5、总结

至此,你已经建立对 Laravel Boardcast 的基本认识,成功入门「广播系统」。

另外,Laravel 5.6 新增一条关于 Broadcast 的新特性,避免在 routes/channels.php 文件内编写众多闭包导致的难以维护。详情可查看:Laravel 5.6 新版特性。

其实,本文只不过抛砖引玉而已。对于部署到生产环境,仍然存在许多问题,例如:

与常见 PHP 应用不同,广播基于 WebSocket 长连接;那么如何确保通信稳定性,如何剔除死链?

为了确保应用访问速度,广播通常是异步执行的;那么如何配置事件队列?如何将队列配置为异步?

如何确保 Laravel Echo Server 进程稳定运行?如何处理异常?是否需要关闭 Debug 模式?

如何确保 Laravel Echo 与服务端连接稳定?是否需要定时检查?如何捕捉并完善地处理所有异常?

客户端收听私有频道,若被服务器拒绝,是否需要断开连接?如何给予用户友好地提示?

……

当然,这些问题本文没有提到,但网络上已经有无数成熟、便捷的解决方案;更多高级用法也可以参照本文最初列出的官方文档。

以上就是本篇文章的全部内容了,更多内容请关注laravel入门教程!

相关文章推荐:

Laravel框架中管道设计模式之中间件的基本工作原理

Laravel框架实现发送短信验证功能代码,laravel发送短信

相关课程推荐:

全方位解读Laravel框架及实战视频教程

2017年最新的五个Laravel视频教程推荐

以上是Laravel框架内置的Broadcast功能如何实现与客户端实时通信的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
使用Laravel:使用PHP简化Web开发使用Laravel:使用PHP简化Web开发Apr 19, 2025 am 12:18 AM

Laravel优化Web开发流程的方法包括:1.使用路由系统管理URL结构;2.利用Blade模板引擎简化视图开发;3.通过队列处理耗时任务;4.使用EloquentORM简化数据库操作;5.遵循最佳实践提高代码质量和可维护性。

Laravel:PHP Web框架的简介Laravel:PHP Web框架的简介Apr 19, 2025 am 12:15 AM

Laravel是一个现代化的PHP框架,提供了强大的工具集,简化了开发流程并提高了代码的可维护性和可扩展性。1)EloquentORM简化数据库操作;2)Blade模板引擎使前端开发直观;3)Artisan命令行工具提升开发效率;4)性能优化包括使用EagerLoading、缓存机制、遵循MVC架构、队列处理和编写测试用例。

Laravel:MVC建筑和最佳实践Laravel:MVC建筑和最佳实践Apr 19, 2025 am 12:13 AM

Laravel的MVC架构通过模型、视图、控制器分离数据逻辑、展示和业务处理,提高了代码的结构化和可维护性。1)模型处理数据,2)视图负责展示,3)控制器处理用户输入和业务逻辑,这种架构让开发者专注于业务逻辑,避免陷入代码泥潭。

Laravel:解释的主要功能和优势Laravel:解释的主要功能和优势Apr 19, 2025 am 12:12 AM

Laravel是一个基于MVC架构的PHP框架,具有简洁的语法、强大的命令行工具、便捷的数据操作和灵活的模板引擎。1.优雅的语法和易用的API使开发快速上手。2.Artisan命令行工具简化了代码生成和数据库管理。3.EloquentORM让数据操作直观简单。4.Blade模板引擎支持高级视图逻辑。

用Laravel建造后端:指南用Laravel建造后端:指南Apr 19, 2025 am 12:02 AM

Laravel适合构建后端服务,因为它提供了优雅的语法、丰富的功能和强大的社区支持。1)Laravel基于MVC架构,简化了开发流程。2)它包含EloquentORM,优化了数据库操作。3)Laravel的生态系统提供了如Artisan、Blade和路由系统等工具,提升开发效率。

laravel框架技巧分享laravel框架技巧分享Apr 18, 2025 pm 01:12 PM

在这个技术不断进步的时代,掌握先进的框架对于现代程序员至关重要。本文将通过分享 Laravel 框架中鲜为人知的技巧,帮助你提升开发技能。Laravel 以其优雅的语法和广泛的功能而闻名,本文将深入探讨其强大的特性,提供实用技巧和窍门,帮助你打造高效且维护性高的 Web 应用程序。

laravel和thinkphp的区别laravel和thinkphp的区别Apr 18, 2025 pm 01:09 PM

Laravel 和 ThinkPHP 都是流行的 PHP 框架,在开发中各有优缺点。本文将深入比较这两者,重点介绍它们的架构、特性和性能差异,以帮助开发者根据其特定项目需求做出明智的选择。

laravel用户登录功能一览laravel用户登录功能一览Apr 18, 2025 pm 01:06 PM

在 Laravel 中构建用户登录功能是一个至关重要的任务,本文将提供一个全面的概述,涵盖从用户注册到登录验证的每个关键步骤。我们将深入探讨 Laravel 的内置验证功能的强大功能,并指导您自定义和扩展登录过程以满足特定需求。通过遵循这些一步一步的说明,您可以创建安全可靠的登录系统,为您的 Laravel 应用程序的用户提供无缝的访问体验。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境