← กรณีการใช้งาน

Laravel Echo โดยไม่ต้องรัน Reverb

เปลี่ยนค่าใน .env ไม่กี่ค่า อีเวนต์ แชนเนล whisper และ toOthers() ใช้ได้เหมือนเดิม

Laravel Broadcasting ใช้โปรโตคอล Pusher อยู่แล้ว แอป Laravel จึงส่ง broadcast ไปที่ Hibira ได้ด้วยการเชื่อมต่อ pusher ที่มีมาในตัว อีเวนต์ เส้นทางแชนเนล และโค้ด Echo ไม่ต้องเปลี่ยน สิ่งที่หายไปคือเซิร์ฟเวอร์ WebSocket ที่คุณต้องรันเอง ทั้งโปรเซส Reverb ที่รันตลอดเวลา Redis สำหรับขยายเกินหนึ่งเครื่อง load balancer แบบ sticky และคนที่ต้องคอยเฝ้าตอนกลางคืน

สิ่งที่ผู้ใช้ได้รับ

  • สถานะคำสั่งซื้อ การแจ้งเตือน และแดชบอร์ดที่อัปเดตเองโดยไม่ต้องรีเฟรช
  • แชตที่มีสถานะ "กำลังพิมพ์…" และรายชื่อคนออนไลน์ ผ่าน join และ whisper ของ Echo
  • สถานะล่าสุดตั้งแต่วินาทีที่เปิดหน้า ไม่ใช่หน้าว่างจนกว่าอีเวนต์ถัดไปจะมา

ฟีเจอร์ที่ใช้

  • 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: broadcast อีเวนต์ถึงลูกค้าคนเดียว

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: สถานะล่าสุดสำหรับทุกหน้าที่เปิดใหม่

broadcast บนแชนเนลที่ชื่อขึ้นต้นด้วย 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 จะมีการตั้งค่าเดียวกันที่กรอกค่าของแอปคุณไว้ให้

เคล็ดลับ

  • สร้างแอปแยกสำหรับแต่ละสภาพแวดล้อม (local, staging, production) อีเวนต์ทดสอบจะได้ไม่ไปถึงผู้ใช้จริง
  • แชนเนล presence รองรับสมาชิกได้สูงสุด 100 คน ห้องที่ใหญ่กว่านั้นดูผู้ชมจำนวนมาก
  • broadcast แต่ละครั้งนับเป็นหนึ่งข้อความไม่ว่าจะมีกี่เบราว์เซอร์ได้รับ การส่งถึงและการอัปเดต presence ไม่มีค่าใช้จ่าย