---
# System prepended metadata

title: Laravel Websockets & Pub-Sub(廣播訂閱)
tags: [開發經驗分享, Laravel]

---


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

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

## Pub-Sub(廣播訂閱)

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

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

## 伺服器推播
在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)



