搜尋
首頁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中構建具有高級功能的寧靜API?如何在Laravel中構建具有高級功能的寧靜API?Mar 11, 2025 pm 04:13 PM

本文指導建立強大的Laravel Restful Apis。 它涵蓋項目設置,資源管理,數據庫交互,序列化,身份驗證,授權,測試和關鍵的安全性最佳實踐。 解決可伸縮性chall

如何在Laravel中實施OAuth2身份驗證和授權?如何在Laravel中實施OAuth2身份驗證和授權?Mar 12, 2025 pm 05:56 PM

本文詳細介紹了Laravel實施OAuth 2.0身份驗證和授權。 它涵蓋了使用League/oauth2-server或提供商特定解決方案的軟件包,強調數據庫設置,客戶端註冊,授權服務器Configu

如何使用Laravel的組件來創建可重複使用的UI元素?如何使用Laravel的組件來創建可重複使用的UI元素?Mar 17, 2025 pm 02:47 PM

本文討論了使用組件在Laravel中創建和自定義可重複使用的UI元素,從而為組織提供最佳實踐並建議增強包裝。

在雲原生環境中使用Laravel的最佳實踐是什麼?在雲原生環境中使用Laravel的最佳實踐是什麼?Mar 14, 2025 pm 01:44 PM

本文討論了在雲本地環境中部署Laravel的最佳實踐,重點是可擴展性,可靠性和安全性。關鍵問題包括容器化,微服務,無狀態設計和優化策略。

如何在Laravel中創建和使用自定義刀片指令?如何在Laravel中創建和使用自定義刀片指令?Mar 17, 2025 pm 02:50 PM

本文討論了Laravel中的創建和使用自定義刀片指令以增強模板。它涵蓋了定義指令,在模板中使用它們,並在大型項目中管理它們,強調了改進的代碼可重複性和R等好處

如何在Laravel中創建和使用自定義驗證規則?如何在Laravel中創建和使用自定義驗證規則?Mar 17, 2025 pm 02:38 PM

本文討論了Laravel中的創建和使用自定義驗證規則,提供了定義和實施的步驟。它突出了諸如可重複性和特異性之類的好處,並提供了擴展Laravel驗證系統的方法。

Laravel vs. Symfony:哪個適合您的Web應用程序?Laravel vs. Symfony:哪個適合您的Web應用程序?Mar 10, 2025 pm 01:34 PM

在選擇PHP框架方面,Laravel和Symfony是最受歡迎和廣泛使用的選項之一。每個框架都為桌子帶來了自己的理念,特徵和優勢,使它們適合不同的項目和用例

在Laravel中處理文件上傳和雲存儲的最佳方法是什麼?在Laravel中處理文件上傳和雲存儲的最佳方法是什麼?Mar 12, 2025 pm 05:54 PM

本文探討了Laravel中最佳的文件上傳和雲存儲策略。 它檢查本地存儲與雲提供商(AWS S3,Google Cloud,Azure,Digitalocean),強調安全性(驗證,消毒,HTTPS)和Performance Opti

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 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境