Laravel Reverb:原生 WebSocket
Laravel Reverb 是 Laravel 11 引入的官方原生 WebSocket 服务器,基于 PHP 8.3 的 Fiber 异步模式实现,不依赖 Node.js,不需要付费 Pusher。单台服务器可以支撑数十万并发连接。
安装
php artisan install:broadcasting
# 安装 Reverb、Echo 和 Pusher JS 客户端库
# 发布 config/broadcasting.php 和 config/reverb.php
# 添加 .env 中的 BROADCAST_CONNECTION=reverb
# .env
BROADCAST_CONNECTION=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
REVERB_SCHEME=http # 生产环境用 https
# 前端连接配置
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
启动 Reverb 服务器
# 启动 WebSocket 服务器
php artisan reverb:start
# → 默认监听 0.0.0.0:8080
# 指定 host/port
php artisan reverb:start --host=0.0.0.0 --port=8080
# 生产环境(后台运行,用 Supervisor 管理)
# 见下方 Supervisor 配置
广播事件:三种频道类型
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
// 1. 公共频道(任何人都可以订阅)
class PublicAnnouncement implements ShouldBroadcast
{
public function broadcastOn(): array
{
return [new Channel('announcements')];
}
}
// 2. 私有频道(需要认证,用于个人通知)
class NewMessageReceived implements ShouldBroadcast
{
public function __construct(
private Message $message
) {}
public function broadcastOn(): array
{
return [new PrivateChannel('user.' . $this->message->recipient_id)];
}
public function broadcastWith(): array
{
return [
'id' => $this->message->id,
'content' => $this->message->content,
'from' => $this->message->sender->name,
'at' => $this->message->created_at->toISOString(),
];
}
// 广播时的事件名(前端监听用)
public function broadcastAs(): string
{
return 'new.message';
}
}
// 3. Presence 频道(知道谁在线,适合协作场景)
class TaskUpdated implements ShouldBroadcast
{
public function __construct(private Task $task) {}
public function broadcastOn(): array
{
return [new PresenceChannel('project.' . $this->task->project_id)];
}
}
频道认证(私有/Presence 频道)
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;
use App\Models\Project;
// 私有频道认证:当前用户是否允许订阅
Broadcast::channel('user.{userId}', function ($user, int $userId) {
return $user->id === $userId; // 只能订阅自己的频道
});
// Presence 频道认证(返回用户信息而不是 true/false)
Broadcast::channel('project.{projectId}', function ($user, int $projectId) {
$project = Project::find($projectId);
if ($project?->hasMember($user)) {
return [
'id' => $user->id,
'name' => $user->name,
'avatar' => $user->avatar_url,
];
}
return false; // 不允许加入
});
前端:Laravel Echo + Reverb
// resources/js/echo.js(或 bootstrap.js)
import Echo from 'laravel-echo';
import Pusher from 'pusher-js'; // Reverb 兼容 Pusher 协议
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 ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
// Vue / React 中监听事件
// 1. 监听私有频道
const userId = auth.user.id;
Echo.private(`user.${userId}`)
.listen('.new.message', (event) => {
console.log('新消息:', event.content);
notifications.push(event);
});
// 2. 监听 Presence 频道(协作场景)
Echo.join(`project.${projectId}`)
.here((members) => {
console.log('当前在线成员:', members);
setOnlineMembers(members);
})
.joining((member) => {
console.log(member.name, '加入了');
})
.leaving((member) => {
console.log(member.name, '离开了');
})
.listen('.task.updated', (event) => {
updateTask(event);
});
// 3. 取消监听(组件卸载时)
Echo.leave(`project.${projectId}`);
Echo.leaveAllChannels();
生产环境:Supervisor + Nginx 反向代理
; Supervisor 管理 Reverb
[program:taskflow-reverb]
command=php /var/www/taskflow/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/www/taskflow/storage/logs/reverb.log
# Nginx:把 WebSocket 请求代理到 Reverb
server {
listen 443 ssl;
server_name taskflow.app;
# ... SSL 配置 ...
location /app {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
proxy_read_timeout 60s;
}
}
下一节:Broadcasting 频道认证与前端接入——私有频道和 Presence 频道的认证细节、CSRF 处理,以及如何在 React/Vue 中正确初始化 Echo 实例。