美文网首页
Laravel Reverb 广播使用

Laravel Reverb 广播使用

作者: 王宣成 | 来源:发表于2024-08-28 19:45 被阅读0次

    安装laravel

    composer create-project --prefer-dist laravel/laravel laravel-reverb-chat
    cd laravel-reverb-chat
    

    配置.env

    cp .env.example  .env
    vim .env
    
    php artisan install:broadcasting
    npm install --save laravel-echo pusher-js
    

    查看配置文件已生成

    # .env
    REVERB_APP_ID=836301
    REVERB_APP_KEY=o2kwvwhasspm4ek1u
    REVERB_APP_SECRET=krwrs2wk4oyxpsh
    REVERB_HOST="localhost"
    REVERB_PORT=8080
    REVERB_SCHEME=http
    
    VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
    VITE_REVERB_HOST="${REVERB_HOST}"
    VITE_REVERB_PORT="${REVERB_PORT}"
    VITE_REVERB_SCHEME="${REVERB_SCHEME}"
    

    房间表生成迁移

    php artisan make:model Room --migration
    

    编辑 database/migrations

    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         */
        public function up(): void
        {
            Schema::create('rooms', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->timestamps();
            });
        }
    
        /**
         * Reverse the migrations.
         */
        public function down(): void
        {
            Schema::dropIfExists('rooms');
        }
    };
    
    

    执行迁移

    php artisan migrate
    

    生成数据

    php artisan make:seeder RoomsTableSeeder 
    
    <?php
    
    namespace Database\Seeders;
    
    use Illuminate\Database\Console\Seeds\WithoutModelEvents;
    use Illuminate\Database\Seeder;
    use Illuminate\Support\Facades\DB;
    
    class RoomsTableSeeder extends Seeder
    {
        /**
         * Run the database seeds.
         */
        public function run(): void
        {
            DB::table('rooms')->insert([
                ['name' => 'Room 1'],
                ['name' => 'Room 2'],
                ['name' => 'Room 3'],
                ['name' => 'Room 4'],
                ['name' => 'Room 5'],
            ]);
        }
    }
    

    执行

    php artisan db:seed
    

    创建 app/Events/MessageSent.php

    <?php
    
    namespace App\Events;
    
    use App\Models\ChatMessage;
    use Illuminate\Broadcasting\InteractsWithSockets;
    use Illuminate\Broadcasting\PrivateChannel;
    use Illuminate\Broadcasting\Channel;
    use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
    use Illuminate\Foundation\Events\Dispatchable;
    use Illuminate\Queue\SerializesModels;
    
    class MessageSent implements ShouldBroadcastNow
    {
        use Dispatchable;
        use InteractsWithSockets;
        use SerializesModels;
    
        public $userName;
        public $roomId;
        public $message;
    
        public function __construct($userName, $roomId, $message)
        {
            $this->userName = $userName;
            $this->roomId = $roomId;
            $this->message = $message;
        }
    
        public function broadcastOn() : Channel
        {
    
            return new Channel('chat.' . $this->roomId);
        }
    
        public function broadcastWith()
        {
            return [
                'userName' => $this->userName,
                'message' => $this->message,
            ];
        }
    }
    

    创建 resources/views/rooms/index.blade.php

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Chat Rooms</title>
    </head>
    <body>
    <div id="app">
        <h1>Chat Rooms</h1>
        <ul>
            @foreach($rooms as $room)
                <li>
                    <a href="{{ route('rooms.show', $room->id) }}">Join {{ $room->name }}</a>
                </li>
            @endforeach
        </ul>
    </div>
    </body>
    </html>
    

    创建 resources/views/rooms/chat.blade.php

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Chat Room: {{ $room->name }}</title>
        @vite(['resources/css/app.css'])
        @vite(['resources/js/app.js'])
    </head>
    <body>
    <div id="app">
        <h2>Chat Room: {{ $room->name }}</h2>
        <div id="messages"
             style="border: 1px solid #ccc; margin-bottom: 10px; padding: 10px; height: 300px; overflow-y: scroll;">
            <!-- Messages will be displayed here -->
        </div>
        <input type="text" id="messageInput" placeholder="Type your message here..." autofocus>
        <button onclick="sendMessage()">Send</button>
    </div>
    
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const roomId = "{{ $room->id }}";
            Echo.channel(`chat.${roomId}`)
                .listen('MessageSent', (e) => {
                    const messages = document.getElementById('messages');
                    const messageElement = document.createElement('div');
                    messageElement.innerHTML = `<strong>${e.userName}:</strong> ${e.message}`;
                    messages.appendChild(messageElement);
                    messages.scrollTop = messages.scrollHeight; // Scroll to the bottom
                });
        })
    
        function sendMessage() {
            const messageInput = document.getElementById('messageInput');
            const message = messageInput.value;
            messageInput.value = ''; // Clear input
            const roomId = "{{$room->id}}"
            fetch(`/rooms/${roomId}/message`, {
                method: 'POST',
                headers: {
                    'X-CSRF-TOKEN': '{{ csrf_token() }}',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({message: message})
            }).catch(error => console.error('Error:', error));
        }
    
    </script>
    </body>
    </html>
    

    修改 resources/js/app.js

    import './bootstrap';
    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 ?? 80,
        wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
        forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
        enabledTransports: ['ws', 'wss'],
    });
    

    生成控制器 php artisan make:controller RoomsController

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Models\Room;
    
    class RoomsController extends Controller
    {
        public function index()
        {
            $rooms = Room::all();
            return view('rooms.index',[
                'rooms' => $rooms
            ]);
        }
    
        public function show(Room $room)
        {
            return view('rooms.chat', [
                'roomId' => $room->id,
                'room' => $room,
                'messages' => []
            ]);
        }
    }
    
    

    生成控制器 php artisan make:controller ChatController

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Str;
    use App\Events\MessageSent;
    
    class ChatController extends Controller
    {
        public function postMessage(Request $request, $roomId)
        {
            $userName = 'User_' . Str::random(4);
            $messageContent = $request->input('message');
            MessageSent::dispatch($userName, $roomId, $messageContent);
            return response()->json(['status' => 'Message sent successfully.']);
        }
    }
    
    

    routes/web.php 文件

    <?php
    
    use Illuminate\Support\Facades\Route;
    use App\Http\Controllers\RoomsController;
    use App\Http\Controllers\ChatController;
    
    Route::get('/', function () {
        return view('welcome');
    });
    
    
    Route::get('/rooms', [RoomsController::class, 'index'])->name('rooms.index');
    Route::get('/rooms/{room}', [RoomsController::class, 'show'])->name('rooms.show');
    Route::post('/rooms/{roomId}/message', [ChatController::class, 'postMessage'])->name('api.rooms.message.post');
    

    运行项目

    php artisan serve
    npm run dev
    php artisan queue:listen
    php artisan reverb:start
    # 可以设置特定的主机或端口,默认8080
    php artisan reverb:start --host=127.0.0.1 --port=9000
    

    访问 http://127.0.0.1:8000/rooms

    在https域名下配置, 本地生成证书可以使用 https://github.com/FiloSottile/mkcert

    # nginx 代理
     location /app {  # WebSocket 路径
            proxy_pass http://127.0.0.1:8080;   # Laravel Reverb 运行的地址
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    
    
    # .env
    REVERB_HOST="xxxxx.com"
    REVERB_SCHEME=https
    REVERB_PORT=443
    

    本地开发如果报错cURL error 60: SSL certificate problem: 找到修改为false

    /www/wwwroot/demo/chat/laravel-reverb-chat/vendor/guzzlehttp/guzzle/src/Client.php
    
    'verify' => false,
    

    相关文章

      网友评论

          本文标题:Laravel Reverb 广播使用

          本文链接:https://www.haomeiwen.com/subject/orvtljtx.html