# 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中伺服器的推播 * [Pusher Channels](https://pusher.com/channels/) * [Ably](https://ably.com/) * [laravel-websockets](https://beyondco.de/docs/laravel-websockets/getting-started/introduction) * [soketi](https://docs.soketi.app/) * [Redis](https://laravel.com/docs/10.x/redis#pubsub) ## 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 的廣播功能,我們需要設定廣播路由,使客戶端能夠與服務器建立連接和接收廣播事件。 `ServiceProvider` 的 `boot` 方法設定了 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](https://beyondco.de/docs/laravel-websockets/getting-started/introduction) [Acadeaio/video](https://www.youtube.com/@Acadeaio/videos)