Try   HackMD

Laravel Websockets & Pub-Sub(廣播訂閱)

Request是當用戶在瀏覽器中輸入網址、提交表單等操作,客戶端向服務器端發送的請求。Response則是請求後返回給客戶端的響應。
早期網頁實現動態更新透過輪詢+ajax(Asynchronous JavaScript and XML),計時器不斷向伺服器請求、響應,方法簡單粗暴,但耗費頻寬,每次request、response都夾帶header、cookie的交換。

Pub-Sub(廣播訂閱)

Pub-Sub是一個消息傳遞模式,在發送者和接收者之間傳遞消息。在Pub-Sub中,發送者將消息發送到主題(也稱為通道),而所有已訂閱此主題的接收者都將收到消息。這種模式用於解耦系統中的組件,從而使系統更具可擴展性和靈活性。此外,由於Pub-Sub可以支持多對多的消息傳遞,因此它通常用於需要廣播消息的應用程序,如聊天應用程序或即時更新應用程序。

在Laravel中,透過websockets來實現廣播訂閱模式,當客戶端與伺服器建立起長連結後,一旦事件被觸發,例如新上品上架後,就會觸發事件,廣播到所有訂閱的客戶端。

伺服器推播

在laravel中伺服器的推播

Laravel Websockets安裝

安裝套件

composer require beyondcode/laravel-websockets

註冊Provider

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"

migrate

php artisan migrate

config/websockets.php設定檔

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

App\Providers\BroadcastServiceProvider

在 Laravel 應用程式中,廣播允許服務器主動推送事件給客戶端,以實現即時的數據同步和互動。為了使用 Laravel 的廣播功能,我們需要設定廣播路由,使客戶端能夠與服務器建立連接和接收廣播事件。

ServiceProviderboot 方法設定了 Laravel 的廣播路由,通過調用 Broadcast::routes() 方法,並且導入了頻道路由清單routes/channels.php。這個頻道路由清單列出了應用程式支持的所有頻道,以及與之相關聯的授權回呼函數。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;

class  BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes();

        require base_path('routes/channels.php');
    }
}

連線授權routes\channels.php

客戶端對伺服器端發起授權請求進入channels.php,回呼函式得到正確結果,回傳資料,雙方建立websocket連線

<?php

use Illuminate\Support\Facades\Broadcast;

/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/

Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

Broadcast::channel('presence.chat.{id}', function ($user, $id){
    return $user;
});

建立Event

php artisan make:event demo

Laravel 會自動廣播,有實作ShouldBroadcast介面的事件

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class demo implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('test1');
    }
}

啟動websocket

php artisan websockets:serve

客戶端訂閱

安裝依賴包

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

resources/js/bootstrap.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
});

編譯前端資源

npm run dev

參考資料

Laravel Websockets Doc
Acadeaio/video