Ứng Dụng Real-Time Với Laravel Reverb
Trong nhiều năm, các lập trình viên Laravel dựa vào Pusher (đắt đỏ) hoặc Laravel Echo Server / Soketi (cần Node.js) cho WebSockets.
Laravel 11 giới thiệu Reverb, một WebSocket server được viết trực tiếp bằng PHP (sử dụng Event Loop). Nó cho phép bạn xây dựng các ứng dụng real-time mà không cần rời khỏi hệ sinh thái PHP.
Tại Sao Chọn Reverb?
- Native PHP: Không cần Node.js
- Miễn phí hoàn toàn: Self-hosted, không tính phí theo message
- First-party: Được maintain bởi Laravel team
- Nhanh: Xây dựng trên ReactPHP, xử lý hàng nghìn kết nối
- Đơn giản: Hoạt động với Laravel Broadcasting sẵn có
Cài Đặt
php artisan install:broadcasting
Lệnh này hỏi bạn có muốn cài đặt Reverb không. Chọn "Yes".
Nó cài đặt package, publish cấu hình, và cấu hình môi trường của bạn.
Cài Đặt Thủ Công
composer require laravel/reverb
php artisan reverb:install
Cấu hình .env:
BROADCAST_DRIVER=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
Cách Hoạt Động
- Backend Event: Bạn fire một event trong PHP.
MessageSent::dispatch($message); - Broadcasting: Nếu event implement
ShouldBroadcast, Laravel đẩy nó tới Reverb server (qua Redis hoặc kết nối trực tiếp). - Client (Laravel Echo): Frontend đang lắng nghe một channel và nhận JSON payload ngay lập tức.
Event
namespace App\Events;
use App\Models\Message;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageSent implements ShouldBroadcast
{
public function __construct(
public Message $message
) {}
public function broadcastOn(): array
{
return [
new PrivateChannel('chat.' . $this->message->room_id),
];
}
// Tùy chỉnh payload
public function broadcastWith(): array
{
return [
'id' => $this->message->id,
'content' => $this->message->content,
'user' => $this->message->user->only(['id', 'name', 'avatar']),
'created_at' => $this->message->created_at->toISOString(),
];
}
}
Channel Authorization
Với private channels, định nghĩa authorization trong routes/channels.php:
use App\Models\Room;
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
return Room::find($roomId)?->users->contains($user);
});
Frontend (Laravel Echo)
Cài đặt các packages cần thiết:
npm install laravel-echo pusher-js
Cấu hình Echo trong resources/js/bootstrap.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT,
wssPort: import.meta.env.VITE_REVERB_PORT,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
Lắng nghe events trong component:
Echo.private(`chat.${roomId}`)
.listen('MessageSent', (e) => {
console.log('Tin nhắn mới:', e);
messages.value.push(e);
})
.listenForWhisper('typing', (e) => {
console.log(`${e.name} đang gõ...`);
});
Presence Channels
Theo dõi ai đang online với presence channels:
// routes/channels.php
Broadcast::channel('room.{roomId}', function ($user, $roomId) {
if (Room::find($roomId)?->users->contains($user)) {
return ['id' => $user->id, 'name' => $user->name];
}
});
Echo.join(`room.${roomId}`)
.here((users) => {
onlineUsers.value = users;
})
.joining((user) => {
onlineUsers.value.push(user);
})
.leaving((user) => {
onlineUsers.value = onlineUsers.value.filter(u => u.id !== user.id);
});
Client-Side Events (Whispers)
Gửi events trực tiếp từ client tới client (ví dụ: chỉ báo "đang gõ"):
// Gửi
Echo.private(`chat.${roomId}`).whisper('typing', {
name: currentUser.name
});
// Nhận
.listenForWhisper('typing', (e) => {
typingUser.value = e.name;
});
Chạy Reverb trong Production
Khởi động Reverb server:
php artisan reverb:start
Cho production, sử dụng Supervisor để giữ nó chạy:
[program:reverb]
command=php /var/www/html/artisan reverb:start
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/reverb.log
Khả Năng Mở Rộng với Redis
Để mở rộng theo chiều ngang, Reverb sử dụng Redis Pub/Sub để đồng bộ hóa nhiều servers:
REVERB_SCALING_ENABLED=true
REDIS_HOST=your-redis-host
Điều này cho phép bạn chạy nhiều instances Reverb phía sau load balancer.
Các Trường Hợp Sử Dụng
- Ứng dụng chat
- Trung tâm thông báo
- Metrics dashboard real-time
- Chỉ báo "Người dùng đang gõ..."
- Cộng tác real-time (kiểu Google Docs)
- Điểm số thể thao trực tiếp
- Triển khai multiplayer game
Debugging
Bật debug mode để xem connection logs:
php artisan reverb:start --debug
Real-time không còn "khó" trong PHP nữa. Với Reverb, nó là native, hiệu năng cao, và tiết kiệm chi phí.