← 使用场景

无需自己运行 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 更新不另计费。