Laravel Reverb
Laravel Reverb 是 Laravel 11 新增的一個套件,適用於 Websocket 的應用程式開發,這篇嘗試使用 Laravel Reverb 來建立一個簡單的 Websocket 應用程式。
Laravel 的 Channel 種類:(根據目前查詢到的資料)
Channel
公開的頻道,任何人都可以訂閱
Presence Channel
需要驗證的頻道,只有登入的使用者可以訂閱,
訂閱 並且可以知道有多少人在,他會追蹤頻道訂閱者的狀態
Private Channel
需要驗證的頻道,只有特定的使用者可以訂閱

安裝
php artisan install:broadcasting
啟動服務
php artisan reverb:start --debug # 開發時使用相對來說比較簡單(有打印訊息的話可能會比較慢,正式環境不建議使用)
基礎設定(這邊要確保正確,否則會無法正常運作)
BROADCAST_CONNECTION=reverb
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
Credential - 憑證
REVERB_APP_ID="my-app-id"
REVERB_APP_KEY="my-app-key"
REVERB_APP_SECRET="my-app-secret"
# 如果用 vite 的話
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="localhost"
VITE_REVERB_PORT=8080
VITE_REVERB_SCHEME=http
使用 reverb 是透過事件觸發來推發廣播資訊,因此要先建立事件 event
事件需要實踐
ShouldBroadcast這個介面。
| Laravel 方法 | Laravel 方法回傳 | 必填 | 描述 | Laravel Echo 對應的方法 |
|---|---|---|---|---|
broadcastOn() | 參照: ShouldBroadcast | true | 即將要發送的頻道 (當要發送時,選定要發送的頻道;可以有多個頻道) | Echo.channel('{{ 這裡 }}') |
broadcastAs() | string | false | 監聽事件的名稱,如果未定義則就是 event 本身名稱 但如果有定義的話,前端監聽名稱需要增加 . 為前綴 | Echo.channel('test-channel').listen('{{ 這裡 }}', ev=>{ console.log(ev) }) |
broadcastWith() | array | false | 前端接收到的內容,也就是 listen(‘TestEvent’, ev=>{ 這個 ev }) 改變資料格式 | listen('TestEvent', ev=>{}) 就是這個 ev 可以改變成自己想要的內容 |
開發需要的指令
- 建立事件:
php artisan make:event {{ 事件名稱 }} - (常駐)啟動 queue:work:
php artisan queue:work- 當 event 被改動或是新增時,需要重新啟動 - (常駐)啟動 reverb server:
php artisan reverb:start --debug
嘗試使用:(先使用 Public Channel)
個人習慣是先從簡單的開始測試,如果以廣播來說,公共頻道應該是最簡單的。
事件需要實作 ShouldBroadcast 介面
class TestEvent implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public string $message = '') { /** empty section */ } public function broadcastOn() { return new Channel('test-channel'); } public function broadcastWith(): array { return ['msg' => 'pub channel say: ' . $this->message]; } }由於 Laravel 在跑
install:broadcasting時,會自動幫我們建立一個resources/js/echo.js的檔案,並且加載進入app.js中, 因此我們可以直接使用window.Echo來監聽事件window.Echo.channel('test-channel') .listen('TestEvent', (e) => { console.log(e); });
嘗試使用:(再來是 Private Channel)
Private Channel 需要驗證,因此需要先確認使用者是否登入,
主要多了兩件事情:
- (這框架會默默幫你做掉,但是僅限於 session/cookie 的使用者)使用者登入的認證: 會是我下面說的 /broadcasting/auth 路由
- 多定義 routes/channels.php 的認證方法。 (
broadcastOn()要去想一下怎麼對)app/Events/PrivateEventPublish.phpclass PrivateEventPublish implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public string $message) { } public function broadcastOn(): array { return [ new PrivateChannel('private-channel.' . auth()->id()), ]; } public function broadcastAs(): string { return 'private-event'; } public function broadcastWith(): array { return [ 'msg' => 'from private: ' . $this->message, 'time' => now()->format('Y-m-d H:i:s'), ]; } }
routes/channels.phpBroadcast::channel('private-channel.{id}', function ($user, $id) { return (int) $user->id === (int) $id; });基本上就是看 broadcastOn 的值,去跟 channels.php 去做對應。
也就是: Broadcast::channel()
- 第一個參數為頻道名稱 -> 會對應到
broadcastOn()的值(含辨識值)- 第二個參數為 callback -> 用來判斷是否可以訂閱該頻道
- 這邊的 callback 會有兩個參數,第一個是使用者,第二個是辨識值
一開始機制是使用 session/cookie 來進行驗證,思考看看能否改成 token 來進行驗證
上述,使用
session/cookie來驗證使用者是否登入,那這邊要想辦法改成token的機制。
- 多註冊一個路由,並且幫他掛上驗證的 middleware
Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:sanctum']]);
- 前端 Laravel Echo 要調整驗證路由
window.Echo = new Echo({
// 省略一些設定
// 需要關注的是下列 authorizer 設定
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
fetch('/api/broadcasting/auth', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token'),
},
body: JSON.stringify({
socket_id: socketId,
channel_name: channel.name
})
})
.then(response => response.json())
.then(data => {
callback(false, data);
})
.catch((error) => {
callback(true, error);
});
}
};
},
});
Queue worker vs Reverb server

Broadcasting network 看到的東西進而下去追蹤
Private/Presence/Public Channel
broadcasting 如果是走私有頻道,需要確定認證機制,他會去用 laravel 的
broadcasting/auth路由驗證使用者是否登入

需驗驗證的頻道流程
vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php的routes方法
透過該方法,當執行到客戶端與 ws 建立連線後,隨後會透過broadcasting/auth路由去驗證使用者是否登入,
如果使用者未登入,則會回傳 403,否則回傳需要監聽的頻道資訊。(暫時未看完整個流程)
嘗試找出 broadcasting/auth 的路由做了什麼事:
-
- 從註冊的路由開始追:
vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php
- 從註冊的路由開始追:
-
- 找到對應的 controller:
vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastController.php
- 找到對應的 controller:
-
- 最後再往裡面找,結果發現是一個 Facade…
vendor/laravel/framework/src/Illuminate/Support/Facades/Broadcast.php
- 最後再往裡面找,結果發現是一個 Facade…
到這邊有點卡關,換個方向思考看看
既然他是 Facade,那我直接呼叫呢?
-
- 直接呼叫後又有路可以繼續查了

- 直接呼叫後又有路可以繼續查了
-
- 進到對應的 class 繼續查

- 進到對應的 class 繼續查
-
- 驗證通道

- 驗證通道
-
- 又是 interface…

- 又是 interface…
-
- 進到對應的 class 繼續查
已經快到最後了,這邊的話可以先埋個
dd(method_exists($this->pusher, 'authorizeChannel'))看他會跑去哪裡 看到回傳是true,則進到authorizeChannel方法

- 9. 核發簽證
