Blog

WebSockets in Laravel, ohne einen WebSocket-Server zu betreiben

· Andrij Tkachenko · 5 Min. Lesezeit

Ein Code-Editor-Fenster, über eine Linie mit einer Cloud verbunden, die Live-Updates an vier Browserfenster sendet

Mit Laravel sehen Live-Updates einfach aus. Ein Event implementiert ShouldBroadcast, routes/channels.php legt fest, wer zuhören darf, und Laravel Echo im Browser empfängt es. Eine Bestellung wechselt auf „versendet“, und der Kunde sieht es, ohne die Seite neu zu laden.

Was die Dokumentation nur nebenbei erwähnt: Irgendetwas muss die Verbindung zu jedem geöffneten Browser halten. Laravel selbst beantwortet Anfragen und hört dann auf, deshalb braucht Broadcasting immer einen WebSocket-Server neben Ihrer App. Dieser Beitrag erklärt, warum, was der Betrieb eines solchen Servers in Produktion verlangt und wie Ihre Events und Echo genau so bleiben, wie sie sind, während eine Echtzeit-Cloud die Verbindungen für Sie hält.

Warum Laravel einen WebSocket-Server braucht

Eine Laravel-Anfrage ist kurz. PHP nimmt die Anfrage entgegen, Laravel startet, Ihr Controller antwortet, und der Prozess ist frei für die nächste Anfrage. Genau das macht Laravel schnell und einfach zu hosten, und genau deshalb kann eine Anfrage nicht stundenlang offen bleiben, um einem Browser Updates zu schicken.

Broadcasting besteht deshalb aus zwei Hälften:

  • Ihre App sendet. Wenn Sie broadcast( new OrderUpdated( $order ) ) aufrufen, übergibt Laravel das Event an einen Broadcaster, der es in einer kurzen Anfrage weitergibt. Mit ShouldBroadcast geschieht das in einem Job in der Queue, also führt ihn ein Queue-Worker aus.
  • Etwas anderes stellt zu. Ein WebSocket-Server hält eine offene Verbindung zu jedem Browser, fragt bei Ihrer App nach, wer welchem Private Channel beitreten darf, und gibt jedes Event an die Browser weiter, die zuhören.

Die erste Hälfte ist ganz normales Laravel. Die zweite ist ein eigener, dauerhaft laufender Dienst, und dort steckt die Arbeit.

Einen eigenen WebSocket-Server betreiben

Laravel hat einen WebSocket-Server, den Sie selbst betreiben können, und andere Projekte haben auch einen. Ihn auf dem Laptop zu starten, dauert eine Minute. Ihn für echte Nutzer zu betreiben, verlangt mehr:

  • Einen dauerhaft laufenden Prozess, den ein Prozessmanager am Leben hält und nach einem Absturz neu startet, mit eigenen Logs und eigener Überwachung. Auf Shared Hosting und Serverless-Plattformen lässt er sich gar nicht betreiben.
  • Einen Port, ein Zertifikat und einen Proxy, damit sich Browser über wss:// auf Ihrer Domain verbinden können, und der Proxy muss so eingerichtet sein, dass er WebSockets durchlässt und lange Verbindungen nicht kappt.
  • Platz für viele Verbindungen. Jeder geöffnete Browser ist eine offene Verbindung, und beim Server wie beim Betriebssystem müssen die Limits für Tausende davon gleichzeitig eingestellt sein.
  • Mehr als einen Server, wenn Sie wachsen. Ein einziger Server ist eine einzige Stelle, an der jede Verbindung abbrechen kann. Zwei oder mehr brauchen einen gemeinsamen Kanal, meist Redis, damit ein Event, das an einen von ihnen gesendet wird, auch die Browser erreicht, die mit den anderen verbunden sind.
  • Deploys ohne Ansturm. Ein Neustart des WebSocket-Servers trennt jede Verbindung, und alle Browser verbinden sich gleichzeitig neu. Seiten, die weg waren, verpassen außerdem, was in der Zwischenzeit gesendet wurde, es sei denn, etwas hebt es für sie auf.

Nichts davon ist exotisch, und viele Teams machen das gut. Aber es ist ein zweites System, das Sie neben Ihrer App am Laufen halten müssen, solange die App Live-Funktionen hat.

Oder eine Echtzeit-Cloud hält die Verbindungen

Der andere Weg ist ein gehosteter Dienst als Ihr Broadcaster. Ihre App sendet jedes Event in einer kurzen HTTP-Anfrage, wie sie es mit einem Broadcaster ohnehin tut, und der Dienst hält die Verbindungen, prüft Ihre Channel-Regeln über Ihre App und stellt zu. Ihre Laravel-App bleibt eine normale Laravel-App, auf jedem Host, Serverless eingeschlossen.

Entscheidend ist, dass der Wechsel innerhalb von Laravels eigenem Broadcasting bleibt, sodass sich Ihre Events, Ihre Channels und Ihr Echo-Code nicht ändern.

Laravel Broadcasting auf WordPlus Cloud

Mit WordPlus Cloud besteht der Wechsel aus einer Broadcasting-Verbindung. Ihre .env legt sie fest:

.env
BROADCAST_CONNECTION=wordplus
WORDPLUS_SITE=s1500000007
WORDPLUS_SECRET=…
WORDPLUS_LOCAL_KEY=…

Ihre Channels bleiben in routes/channels.php, mit einem optionalen Argument dafür, was jeder Raum aufbewahrt:

PHP
// The room of an order, orders.1042, for its customer, the last 20 updates kept.
Broadcast::channel( 'orders.{order}', fn ( User $user, Order $order ) => $user->id === $order->customer_id, [ 'history' => 20 ] );

Ihre Events bleiben, wie sie sind, und broadcast( new OrderUpdated( $order ) ) sendet sie. Im Browser bekommt Echo unseren Connector anstelle seines üblichen:

JavaScript
import Echo from 'laravel-echo';
import { WordplusConnector } from '@wordplus/realtime/echo';

window.Echo = new Echo( { broadcaster: WordplusConnector, ...window.wordplusRealtimeConfig } );

Echo.private( 'orders.1042' ).listen( '.updated', ( data ) => showStatus( data.status ) );

Die Direktive @wordplusRealtime in Ihrem Layout schreibt diese Konfiguration samt angemeldetem Nutzer, sodass sich die Seite ohne vorherige Anfrage verbindet. Danach funktioniert alles, was Sie von Echo kennen:

  • Private und Presence Channels, mit here(), joining() und leaving() dafür, wer in einem Raum ist, whisper() für die Anzeige, wer gerade tippt, und notification() für Laravel Notifications.
  • Livewire empfängt Events auf dieselbe Weise, mit #[On( 'echo-private:orders.{order.id},.updated' )].
  • React und Vue nutzen useEcho() aus Laravels eigenen Echo-Paketen, wie es die Starter Kits tun.
  • toOthers() überspringt den Tab, der die Anfrage gesendet hat.

Und dazu, was ein WebSocket-Server allein nicht bietet:

  • Kein WebSocket-Server, den Sie betreiben müssen. Unsere Server halten die Verbindungen, weitere starten, während Ihre App wächst, und eine Seite wechselt ohne Abbruch von einem zum anderen, wenn einer neu startet.
  • Nichts geht bei einer Neuverbindung verloren. Ein Raum bewahrt seine letzten Events auf, sodass eine Seite, die zurückkommt, bekommt, was sie verpasst hat, in der richtigen Reihenfolge.
  • Unterwegs versiegelt. Was Ihre App sendet, wird verschlüsselt übertragen, mit Schlüsseln, die nur Ihre App und Ihre Nutzer haben.
  • Anrufe und Livestreams über dieselbe Verbindung. Anrufe zwischen zwei Personen, Gruppenanrufe und Livestreams, mit fertigem Anrufbildschirm und Player oder mit Ihren eigenen.

Die Laravel-Anleitung enthält die ganze Einrichtung, und die Live-Demo ist ein kleiner Shop, der darauf aufbaut und in dem eine Bestellung in einem anderen Fenster auf „versendet“ wechselt, während Sie klicken.

Für WordPlus Cloud for Apps gelten Preise nach gleichzeitigen Verbindungen, ab 1.000, monatlich oder jährlich abgerechnet. Sehen Sie, was sie für Apps leistet, oder werfen Sie einen Blick auf die Preise für Apps. Fragen zu Ihrer Integration? Schreiben Sie uns.