跳轉到主要內容
套件在推送即時事件時,要把頻道名稱的定義與放行使用者的判定分開設計。套件在 boot() 中註冊的頻道,若與使用端應用程式 routes/channels.php 中的名稱相同,可能會被覆寫。理解這種註冊順序與評估順序,可以減少維護時的錯誤。 本頁參考了 Laravel 官方文件的廣播,以及用於確認的最新版本 v13.42.0 的實作。事件的傳送方式請參閱廣播,提供者的載入請參閱套件自動探索。

頻道授權的機制

訂閱私有頻道時,用戶端會向 /broadcasting/auth 傳送請求。BroadcastController::authenticate() 將處理交給 Broadcast::auth(),由 Broadcaster 依序評估已註冊的回呼。 評估規則如下。
  • 回呼回傳 false 時,會立即拋出 AccessDeniedHttpException。
  • 回傳 true 等真值時,授權在此時成立。
  • 回傳 null 等假值時,會繼續評估下一個註冊的回呼。若沒有任何回呼放行,最後會拋出 AccessDeniedHttpException。
Pusher 與 Reverb 驅動程式會在授權前移除 private- 與 presence- 前綴。因此,註冊的頻道名稱中不要包含前綴。

在套件中註冊頻道

以一個虛構的 Acme\Orders 套件推送訂單狀態變化為例。頻道名稱為 acme.orders.{order},只允許訂單的擁有者訂閱。 在套件的 ServiceProvider 中,於 boot() 內呼叫 Broadcast::channel()。判定委派給套件內的類別。
join() 的第 1 個參數會傳入授權時的使用者。之後的參數是頻道名稱中 {...} 的值。當 {order} 的參數名稱與 Order $order 一致,且型別是 UrlRoutable 的子類別時,路由模型繫結就會生效。
Broadcast::channel() 的 $callback 可以指定 callable,或帶有 join() 方法的類別名稱。指定類別名稱時,Broadcaster::normalizeChannelHandlerToCallable() 會透過容器建立實例,然後呼叫 join()。

使用端應用程式的覆寫

使用端應用程式傳給 withBroadcasting() 的檔案(通常是 routes/channels.php)會在 withBroadcasting() 註冊的 booted 回呼中載入。booted 回呼在所有服務提供者的 boot() 結束後執行,因此套件 boot() 中的註冊會先進行。 Broadcaster::channel() 以頻道名稱為鍵,儲存到內部陣列中。因此,若使用端應用程式註冊了相同的名稱,第 2 次註冊會取代套件的註冊。Laravel 不會把同名註冊視為重複錯誤。 要防止覆寫,請讓頻道名稱唯一。例如像 acme.orders.{order} 這樣加上套件專屬的前綴,使用端應用程式註冊相同名稱的可能性就會降低。 頻道名稱是與用戶端之間公開的約定。一旦決定,請不要變更。變更後,舊的用戶端將無法訂閱。
對於同名頻道,後註冊的會在沒有任何提示的情況下優先。php artisan channel:list 會顯示頻道名稱與解析目標(類別名稱或 Closure),可以確認留下的是哪一個註冊。

頻道選項與守衛

Broadcast::channel() 的第 3 個參數 $options 會作為每個頻道的設定儲存。指定 guards 後,會依序嘗試用於認證的守衛。
省略 guards 時,使用請求的預設使用者($request->user())進行授權。指定 guards 後,會從頭開始依序呼叫 $request->user($guard),並使用最先取得的使用者。若套件不寫死守衛名稱,而是作為設定值公開,使用端應用程式就可以自行選擇。

在測試中確認頻道註冊

已註冊的頻道可以透過驅動程式的 getChannels() 以 Collection 形式取得。鍵就是頻道名稱本身。
授權結果透過對 /broadcasting/auth 的 HTTP 測試來確認。null 與 log 驅動程式的 auth() 不回傳任何內容,因此不能用於此測試。頻道會在應用程式啟動時註冊到預設驅動程式,因此請先在測試用的 phpunit.xml 等處把 BROADCAST_CONNECTION 設為 reverb 或 pusher,再傳送帶認證的請求。
測試應用程式中需要註冊 /broadcasting/auth。這個路由由 Broadcast::routes() 註冊,BroadcastManager::channelRoutes() 只是把相同的處理交給 routes()。若路由已被快取,routes() 不會執行任何操作。

維護時的注意事項

  • 頻道名稱是公開的約定。變更名稱後,現有用戶端將無法訂閱。
  • 以類別為基礎的頻道透過 Container 解析。建構子的相依請使用容器能夠解析的型別。

總結

套件的頻道授權只要在 boot() 中註冊 Broadcast::channel() 即可運作。若使用端應用程式的 routes/channels.php 之後註冊了相同的名稱,套件的授權就會被取代。為頻道名稱加上前綴、把判定拆分到類別中,並用 HTTP 測試確認 /broadcasting/auth 的結果,可以讓套件更易於維護。

參考的一手資料

最後修改於 2026年11月14日