Laravel Broadcasting ve WebSockets Rehberi

# Laravel Broadcasting ve WebSockets ile Real-Time Bu rehber, orta seviye Laravel geliştiricilerinin sunucu tarafında tetiklenen olayları tarayıcıya...

Laravel Broadcasting ve WebSockets Rehberi

Laravel Broadcasting ve WebSockets ile Real-Time

Bu rehber, orta seviye Laravel geliştiricilerinin sunucu tarafında tetiklenen olayları tarayıcıya gerçek zamanlı olarak iletmesini hedefler. İki farklı yaklaşımı ele alacağız: Laravel'in resmi olarak desteklediği Pusher kanalı ve açık kaynak Laravel Reverb WebSocket sunucusu. İkisinin de sunucu tarafı API'si aynıdır; fark, mesajların taşındığı katmandır.

Önkoşullar

  • Laravel 10 veya 11 (Broadcasting API'si bu sürümlerde kararlıdır; Reverb Laravel 11 ile birlikte gelir).
  • PHP 8.1+.
  • Node.js ve npm (frontend derleme için).
  • Queue worker çalıştırabileceğiniz bir ortam. Broadcast olayları varsayılan olarak kuyruğa alınır.
  • config/broadcasting.php dosyasının ve BROADCAST_CONNECTION ortam değişkeninin varlığı. Laravel 11'de varsayılan bağlantı log olarak gelir; gerçek zamanlı iletim için bunu değiştirmeniz gerekir.

Sürüm notu: Laravel 11 öncesinde ortam değişkeni BROADCAST_DRIVER adını taşıyordu; 11 ile BROADCAST_CONNECTION oldu. Eski projelerden gelen kod örneklerinde bu isim farkına dikkat edin.

Broadcasting Kavramları

  • Kanal (Channel): İstemcilerin abone olduğu mantıksal ad. Üç türü vardır: public, private, presence.
  • Olay (Event): ShouldBroadcast arayüzünü uygulayan bir sınıf. broadcastOn() metodu hangi kanala gideceğini belirler.
  • Yetkilendirme (Authorization): private ve presence kanalları için routes/channels.php içinde tanımlanan geri çağırma fonksiyonu, istemcinin o kanala abone olup olamayacağını belirler.

Public kanallar kimlik doğrulaması gerektirmez ve herkes abone olabilir. Hassas veriyi public kanaldan yayınlamak yaygın bir hatadır; kullanıcıya özel veriler her zaman private kanaldan geçmelidir.

Adım 1: Broadcast Servis Sağlayıcısını Etkinleştirme

Laravel 11'de bootstrap/providers.php içinde App\Providers\BroadcastServiceProvider varsayılan olarak yorumlanmış olabilir. config/app.php (Laravel 10) veya ilgili providers dosyasında bu sağlayıcının kayıtlı olduğundan emin olun. routes/channels.php dosyası bu sağlayıcı üzerinden yüklenir.

Adım 2: Reverb'ü Kurma (Self-Hosted Seçenek)

Laravel Reverb, Pusher protokolüyle uyumlu bir WebSocket sunucusudur. Kurulum komutu:

php artisan install:broadcasting

Bu komut laravel/reverb paketini ister, config/reverb.php dosyasını yayınlar, gerekli ortam değişkenlerini .env dosyasına ekler ve frontend için laravel-echo ile pusher-js paketlerini kurar. Ardından:

php artisan reverb:start

Bu komut WebSocket sunucusunu başlatır. Üretimde bu sürecin Supervisor gibi bir araçla ayakta tutulması gerekir; terminal kapanınca süreç sonlanır.

.env içinde tipik olarak şu değerler yer alır:

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=...
REVERB_APP_KEY=...
REVERB_APP_SECRET=...
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http

Bu değerlerin büyük kısmı install:broadcasting tarafından üretilir; elle uydurmayın, komutun ürettiği değerleri kullanın.

Adım 3: Pusher veya Benzeri Bir Servis Kullanma

Yönetilen bir servis tercih ediyorsanız BROADCAST_CONNECTION=pusher ayarlayın ve PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_CLUSTER değerlerini sağlayıcının panosundan alın. Sunucu tarafı kod aynı kalır; yalnızca taşıma katmanı değişir. Bu, ileride Reverb'den Pusher'a (veya tersine) geçişi kolaylaştırır.

Adım 4: Bir Broadcast Olayı Tanımlama

<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderStatusChanged implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel('orders.'.$this->order->user_id)];
    }

    public function broadcastAs(): string
    {
        return 'order.status.changed';
    }

    public function broadcastWith(): array
    {
        return [
            'id' => $this->order->id,
            'status' => $this->order->status,
        ];
    }
}

Beklenen davranış: event(new OrderStatusChanged($order)) çağrıldığında olay kuyruğa alınır, worker işlediğinde orders.{userId} private kanalına order.status.changed adıyla yalnızca broadcastWith içinde dönen veri gönderilir. broadcastWith tanımlamazsanız public özelliklerin tamamı yayınlanır; bu, model alanlarının istemeden sızmasına yol açabilir. Yalnızca gönderilmesi gereken alanları açıkça listeleyin.

broadcastAs kullanıldığında istemci tarafında dinleyici adı olarak sınıf adını değil, bu kısa adı kullanmanız gerekir. Karışıklığın en sık yaşandığı nokta budur.

Adım 5: Kanal Yetkilendirmesi

routes/channels.php içinde:

use App\Models\Order;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{userId}', function ($user, $userId) {
    return (int) $user->id === (int) $userId;
});

Geri çağırma true dönerse abonelik onaylanır, aksi halde HTTP 403 döner. presence kanalları için dizi döndürmeniz gerekir; bu dizi diğer abonelere "kimler burada" bilgisi olarak iletilir.

private kanallar için yetkilendirme uç noktası /broadcasting/auth yoludur ve web middleware grubuna bağlıdır; yani auth oturumu gerekir. API tabanlı istemcilerde Sanctum gibi bir kimlik doğrulama katmanı kullanmanız gerekir; aksi halde yetkilendirme isteği 401 döner.

Adım 6: Frontend Tarafı

install:broadcasting komutu resources/js/echo.js dosyasını oluşturur. bootstrap.js içinde bu dosyanın içe aktarıldığından emin olun. Tipik bir kurulum:

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'],
});

Abonelik ve dinleme:

window.Echo.private(`orders.${userId}`)
    .listen('.order.status.changed', (payload) => {
        console.log('Sipariş güncellendi:', payload);
    });

listen içindeki nokta ile başlayan isim, broadcastAs ile eşleşmelidir. broadcastAs tanımlamadıysanız baştaki noktayı kaldırıp tam sınıf adını (App.Events.OrderStatusChanged biçiminde) kullanmanız gerekir.

Adım 7: Kuyruk Worker'ı Çalıştırma

ShouldBroadcast kullanan olaylar kuyruğa alınır. Worker çalışmıyorsa olay hiçbir zaman yayınlanmaz ve istemci hiçbir şey almaz. Geliştirme ortamında:

php artisan queue:work

Anlık yayın istiyorsanız ShouldBroadcastNow arayüzünü kullanabilirsiniz; bu, kuyruğu atlar ancak isteği yavaşlatır. Yüksek trafikli uç noktalarda tercih edilmemelidir.

Yaygın Hatalar

  • Kanal adı uyuşmazlığı: Sunucuda orders.{userId}, istemcide orders.${userId} aynı olmalıdır. Tire, nokta ve büyük/küçük harf farkı sessiz başarısızlığa yol açar.
  • broadcastAs unutmak veya iki tarafta farklı yazmak: İstemci hiçbir olay almaz; konsolda hata görünmez.
  • ShouldBroadcast yerine düz olay: Kuyruk devreye girmez, yayın hiç gerçekleşmez.
  • BROADCAST_CONNECTION=log: Olaylar dosyaya yazılır, ağa çıkmaz. Geliştirme sırasında sık karıştırılır.
  • Private kanal için yetkilendirmeyi unutmak: Abonelik 403 ile reddedilir; tarayıcı konsolunda görünür.
  • broadcastWith tanımlamamak: Modelin tüm public alanları yayınlanır; hassas alanlar sızabilir.
  • Reverb sürecinin çöktüğünü fark etmemek: WebSocket bağlantısı sessizce kopar; üretimde süreç izleme şarttır.

Güvenlik Notları

  • Private ve presence kanallarını varsayılan tercih haline getirin. Public kanalı yalnızca gerçekten herkese açık veri için kullanın.
  • routes/channels.php içindeki yetkilendirme fonksiyonunda $user nesnesini kullanarak kaynak sahipliğini doğrulayın; istemciden gelen userId değerine körü körüne güvenmeyin.
  • broadcastWith ile yalnızca gerekli alanları gönderin. Eloquent modellerini olduğu gibi yayınlamak, ilişkilerin ve gizli olmayan alanların dışarı sızmasına yol açar.
  • Reverb'ü üretimde TLS arkasında (wss) çalıştırın. Düz ws üzerinden gönderilen yetkilendirme jetonları ve mesajlar dinlenebilir.
  • REVERB_APP_SECRET ve Pusher anahtarlarını istemciye sızdırmayın. Yalnızca VITE_ önekli, tarayıcıda görünmesi amaçlanan değerleri paketleyin.
  • Yetkilendirme uç noktasını rate limit altına alın; aksi halde kanal adlarını deneyerek bilgi toplama girişimleri mümkün olur.

Kapanış

Sunucu tarafı API'si taşıma katmanından bağımsızdır: ShouldBroadcast uygulayan bir olay, broadcastOn ile kanal, routes/channels.php ile yetki ve broadcastWith ile yük tanımladığınızda hem Reverb hem Pusher ile aynı kod çalışır. Gerçek zamanlı özelliklerde sorunların çoğu taşıma katmanında değil, kanal adı ve olay adı uyuşmazlıkları ile kuyruk worker'ının çalışmamasından kaynaklanır. Bu iki noktayı önce kontrol edin.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz