← 使用情境

不必自己跑 Reverb 的 Laravel Echo

改幾個 .env 值,事件、頻道、whisper 與 toOthers() 照常運作。

Laravel Broadcasting 本來就使用 Pusher 協定,所以 Laravel 應用程式用內建的 pusher 連線就能把廣播送到 Hibira。事件、頻道路由與 Echo 程式碼都不用改。省下的是原本要自己跑的 WebSocket 伺服器:長時間執行的 Reverb 行程、超過一台機器時用來擴展的 Redis、黏性負載平衡,以及半夜得有人盯著它。

使用者得到什麼

  • 訂單狀態、通知與儀表板不必重新整理就會更新。
  • 透過 Echo 的 join 與 whisper,做出有「輸入中…」提示與上線名單的聊天。
  • 頁面一打開就是最新狀態,不會在下一個事件到來前一片空白。

用到的功能

  • Laravel Broadcasting,使用 pusher 連線與 pusher/pusher-php-server。
  • 瀏覽器端的 Laravel Echo 搭配 pusher-js。
  • 私有頻道與 presence 頻道,由你自己的 routes/channels.php 授權。
  • 用戶端事件(Echo whisper)與排除發送者(toOthers())。
  • 快取頻道(cache-),把最後一則事件交給每位新訂閱者。

步驟 1:把 Broadcasting 指向 Hibira

Laravel 11 以後,安裝 broadcasting,詢問時選擇 Pusher:

php artisan install:broadcasting
composer require pusher/pusher-php-server
npm install --save-dev laravel-echo pusher-js

接著在 .env 設定連線,數值來自你的應用程式頁面:

BROADCAST_CONNECTION=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_HOST=ws.hibira.io
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=ap

VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"

Laravel 10 以前請用 BROADCAST_DRIVER=pusher 取代 BROADCAST_CONNECTION。預設的 config/broadcasting.php 已經會把 host、port 與 scheme 傳給 Pusher 函式庫;如果你的設定檔是手寫的,請確認 options 有讀取這些值,才不會連到 pusher.com。

步驟 2:設定 Echo

// resources/js/echo.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: 'ap',
  wsHost: import.meta.env.VITE_PUSHER_HOST,
  wsPort: import.meta.env.VITE_PUSHER_PORT,
  wssPort: import.meta.env.VITE_PUSHER_PORT,
  forceTLS: import.meta.env.VITE_PUSHER_SCHEME === 'https',
  enabledTransports: ['ws', 'wss'],
});

步驟 3:把事件廣播給單一顧客

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

    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel('orders.'.$this->order->id)];
    }
}

// routes/channels.php
Broadcast::channel('orders.{id}', fn ($user, $id) => $user->orders()->whereKey($id)->exists());

// Wherever the order ships
OrderShipped::dispatch($order);
Echo.private(`orders.${orderId}`)
  .listen('OrderShipped', (e) => showStatus(e.order));

ShouldBroadcast 事件會經過你的佇列,所以必須有 worker(php artisan queue:work)在跑。專案沒有佇列時,改用 ShouldBroadcastNow 在請求當下發布。

步驟 4:presence、whisper 與 toOthers()

Echo.join(`room.${roomId}`)
  .here((users) => online.set(users))
  .joining((user) => online.add(user))
  .leaving((user) => online.remove(user))
  .listen('MessageSent', (e) => messages.append(e.message))
  .listenForWhisper('typing', (e) => typing.show(e.name, 3000));
broadcast(new MessageSent($message))->toOthers();

Whisper 是用戶端事件:請在應用程式設定中開啟 Allow client events。toOthers() 透過 X-Socket-ID 標頭跳過發送者自己的分頁,Echo 會自動把它加到 Axios 請求;用 fetch 的話,請自己送出 'X-Socket-ID': Echo.socketId()。完整的聊天室請看聊天使用情境。

步驟 5:每個新頁面都拿到最新狀態

在名稱以 cache- 開頭的頻道上廣播,之後才訂閱的人會立刻收到最後一則事件(保留 30 分鐘):

public function broadcastOn(): array
{
    return [new Channel('cache-scoreboard')];
}
Echo.channel('cache-scoreboard')
  .listen('ScoreUpdated', (e) => board.render(e.scores));

Echo.private('cache-orders.1') 也一樣,會變成 private-cache-orders.1 頻道。

從 Reverb 或其他相容 Pusher 的服務換過來

只有 .env 的值會變:事件、頻道路由與 Echo 程式碼都不變,所以可以一次切換一個環境,要換回去也一樣簡單。遷移頁面列出要檢查的項目,登入後 Laravel 指南會用你的應用程式數值填好同樣的設定。

小提醒

  • 每個環境(本機、測試、正式)各建一個應用程式,測試事件就不會送到真正的使用者。
  • presence 頻道最多 100 位成員。更大的房間請看大量觀眾。
  • 每次廣播不論有多少瀏覽器收到,都只算一則訊息;送達與 presence 更新不另計費。