人称外号大脸猫

在 Laravel 中使用 Reverb 构建高性能 WebSocket 服务指南

一、为什么选择 Laravel Reverb?

Laravel Reverb 是 Laravel 官方推出的 WebSocket 服务解决方案,具有以下优势:

  • 原生集成:与 Laravel 广播系统无缝协作
  • 高性能:基于 PHP 的 WebSocket 实现,无需额外语言栈
  • 零延迟:支持实时双向通信
  • 开发友好:简化配置流程,提供开箱即用的调试工具

二、安装与基础配置

  1. 安装广播系统
php artisan install:broadcasting
  1. 环境变量配置(.env)
# 广播驱动配置
BROADCAST_CONNECTION=reverb

# Reverb 服务端配置
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080

# 客户端连接配置
REVERB_APP_ID=755155
REVERB_APP_KEY=smnwy3e75kdonbv50uza
REVERB_APP_SECRET=cehxutli28eauptn60nc
REVERB_HOST="wss.xxxxx.com"  # 客户端访问域名
REVERB_PORT=443              # 客户端访问端口
REVERB_SCHEME=https

# Vite 前端配置
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

端口模式选择:

  • IP直连:使用 REVERB_SERVER_PORT + REVERB_PORT
  • 域名访问:配置 REVERB_HOST 为域名

三、启动与管理服务

基础启动

php artisan reverb:start

高级选项

# 自定义主机/端口
php artisan reverb:start --host=127.0.0.1 --port=9000

# 调试模式
php artisan reverb:start --debug

# 服务重启
php artisan reverb:restart

四、Nginx 反向代理配置

server {
    listen 443 ssl;
    server_name wss.yuxibs.com;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        
        # 指向本地 Reverb 服务
        proxy_pass http://0.0.0.0:8080; 
    }
}

五、前端实现(Vue3 示例)

<script setup>
import { ref, onUnmounted } from 'vue';
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;
const message = ref('');
const channelName = ref('public.channel');
const messageList = ref([]);

// 初始化 Echo 实例
const ws_echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

// 监听频道消息
ws_echo.channel(channelName.value)
    .listen('.message.created', (event) => {
        messageList.value.push(event);
    })
    .error(console.error);

// 发送消息
const handleSendMessage = async () => {
    await axios.post(route('send-message'), {
        message: message.value,
        channel: channelName.value
    });
    message.value = '';
};

// 组件卸载时断开连接
onUnmounted(() => ws_echo.leave(channelName.value));
</script>

<template>
    <div class="container">
        <ul>
            <li v-for="(item, index) in messageList" :key="index">
                {{ item.message }} @ {{ item.time }}
            </li>
        </ul>
        
        <div class="input-group">
            <input v-model="message" placeholder="输入消息" />
            <button @click="handleSendMessage">发送</button>
        </div>
    </div>
</template>

六、后端实现

  1. 路由配置(routes/web.php)
use App\Events\MessageCreated;
use Illuminate\Support\Facades\Route;

Route::post('/send-message', function (Request $request) {
    event(new MessageCreated(
        message: $request->input('message'),
        channel: $request->input('channel'),
    ));
    
    return response()->json(['status' => 'success']);
})->name('send-message');
  1. 事件类(app/Events/MessageCreated.php)
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;

class MessageCreated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets;

    public function __construct(
        public string $message, 
        public string $channel
    ) {}

    // 动态指定广播频道
    public function broadcastOn(): Channel
    {
        return new Channel($this->channel);
    }

    // 自定义广播数据
    public function broadcastWith(): array
    {
        return [
            'message' => $this->message,
            'time' => now()->toDateTimeString()
        ];
    }

    // 自定义事件名称
    public function broadcastAs(): string
    {
        return 'message.created';
    }
}

七、核心功能解析

  1. 事件广播流程:

  2. 关键技术点:

  • 动态频道管理:通过构造函数参数动态指定广播频道
  • 队列支持:通过 $connection 和 $queue 属性配置队列驱动
  • 事件命名空间:使用 broadcastAs() 自定义前端监听的事件名
  • 安全传输:forceTLS 强制使用加密连接

八、常见问题解决

连接失败检查清单

  • 确保 php artisan reverb:start 服务正常运行
  • 检查防火墙是否开放对应端口
  • 验证 Nginx 配置中 Upgrade 和 Connection 头是否正确设置
  • 前端检查 forceTLS 配置是否与访问协议匹配
  • 使用 --debug 参数查看服务端日志

性能优化建议

# 使用 supervisor 管理进程
[program:reverb]
command=php /path/to/artisan reverb:start --port=8080
autostart=true
autorestart=true
user=www-data

值得注意点是

echo.channel(channelName.value).listen('.message.created', (e) => {});

listen 如果是事件通过broadcastAs 设置了别名 listen '.message.created' 事件名需要加一个点

如果没有设置 listen监听原事件 MessageCreated 而不是 'App\\\\Events\\\\MessageCreated'

推送消息的方法

broadcast(new MessageCreated(
    message: $request->input('message'),
    channel: $request->input('channel'),
));
// 可以加 ->toOthers();  不用发送给自己了

event(new MessageCreated(
    message: $request->input('message'),
    channel: $request->input('channel'),
));
copyright ©2025 ahimu.com all rights reserved 皖ICP备19021547号-1