Panoramica
Il livello di broadcasting di Laravel ha da tempo offerto Reverb, Pusher e Ably come driver “WebSocket-native”. Ora è stato aggiunto un nuovo valoremercure per il driver in config/broadcasting.php.
Mercure è un protocollo real-time costruito sui Server-Sent Events (SSE) invece che su una connessione WebSocket bidirezionale. Si comporta più come un long-polling HTTP/1.1 o HTTP/2, il che gli conferisce alcune caratteristiche distintive:
- Attraversa in modo trasparente la normale infrastruttura HTTP (reverse proxy, CDN, load balancer).
- I client possono essere implementati senza altro che l’API
EventSourcedel browser — nessuna libreria client dedicata richiesta. - FrankenPHP include un hub Mercure integrato, quindi non serve alcuna infrastruttura aggiuntiva per provarlo.
Il nuovo valore driver
Il commento con l’elenco dei driver supportati in cima a config/broadcasting.php ora include mercure:
url viene omesso, il driver ricade sull’hub Mercure integrato di FrankenPHP (la funzione mercure_publish()). Questa decisione avviene in CreatesMercureDrivers::mercure():
url dovrebbe puntare all’API di management usata per la pubblicazione, mentre public_url è l’URL a cui si connette il browser. Separare i due permette configurazioni in cui la pubblicazione avviene su una rete interna (ad esempio Docker Compose) mentre solo l’URL pubblico è esposto al browser.
Token separati per publish e subscribe
Mercure è un protocollo di controllo accessi basato su JWT. Il traitCreatesMercureDrivers costruisce factory di token separate per la pubblicazione (server → hub) e la sottoscrizione (browser → hub):
secret,publish_secretesubscribe_secretpossono essere configurati in modo indipendente, con fallback susecret.- Allo stesso modo
algorithm,publish_algorithmesubscribe_algorithmpossono essere impostati per ogni lato (defaultHS256). - HS256 richiede un secret di almeno 32 byte, HS384 almeno 48 e HS512 almeno 64; in caso contrario viene sollevata una
InvalidArgumentException.
Grant::ACTION_PUBLISH per ogni topic (*) ed è memoizzato da CachingTokenProvider, così non viene generato un nuovo JWT a ogni singola chiamata di broadcast.
Autorizzazione dei canali tramite un singolo cookie
La più grande differenza architetturale rispetto ai driver WebSocket è che l’autorizzazione del sottoscrittore avviene tramite un unico cookie.MercureBroadcaster::auth() accetta un array channel_names (limitato a 100 per richiesta), valuta l’autorizzazione per ciascun canale e poi emette un unico cookie di autorizzazione che li copre tutti:
denied: true nel payload di risposta, mentre gli altri canali autorizzati continuano a funzionare. Questo è cruciale perché Mercure multiplexa molti topic su una sola connessione EventSource, quindi i canali possono essere aggiunti o rimossi a metà sessione senza dover chiudere la connessione.
I canali presence ricevono una struttura Grant diversa rispetto ai normali canali private/private-encrypted, mirata al pattern di URL di sottoscrizione usato dall’API Subscription di Mercure.
Canali cifrati end-to-end
I canali con prefissoprivate-encrypted- sono trattati come cifrati end-to-end (E2EE) — il che significa che nemmeno l’hub Mercure vede il payload. È una funzionalità che i driver Pusher e Reverb esistenti non offrono.
Impostare una encryption_key di 32 byte codificata in base64 attiva il ChannelEncrypter, che avvolge il nome dell’evento, il payload e il socket ID in un JWE (JSON Web Encryption) prima che broadcast() lo invii. L’hub inoltra sempre e solo byte cifrati.
jwk (JSON Web Key) restituito dalla risposta di auth() — uno scambio di chiavi out-of-band raccomandato dalla specifica Mercure, in modo che l’hub non venga mai a conoscenza della chiave.
I canali presence non possono essere cifrati, perché la loro lista dei membri passa per design attraverso l’API Subscription dell’hub — cosa incompatibile con l’E2EE.
Whisper (messaggi diretti client-to-client)
Quandoclient_events è abilitato (impostazione predefinita), a ogni canale protetto viene assegnato un “topic whisper” dedicato su cui i sottoscrittori possono pubblicare:
Convenzioni di naming dei topic
Poiché gli hub Mercure sono spesso condivisi tra più applicazioni, i topic vengono inseriti in un namespace tramite untopic_prefix per evitare collisioni. Il default è:
.alt è un suffisso DNS riservato e non risolvibile (RFC 9476), quindi non può mai collidere con un dominio reale. I nomi dei canali sono URL-encoded secondo l’RFC 3986 in un singolo segmento di path:
Dominio del cookie e messaggi di errore
Dato che un hub Mercure spesso gira su un sottodominio diverso da quello dell’applicazione (per esempiomercure.example.com contro app.example.com), un fallimento nella risoluzione di un dominio cookie condiviso solleva un’eccezione descrittiva:
__Secure- o __Host-, il driver verifica anche in fase di boot che public_url sia in HTTPS:
Scegliere tra Reverb, Pusher/Ably e Mercure
Mercure è una buona scelta quando non ti serve una connessione bidirezionale persistente — notifiche, aggiornamenti di avanzamento o casi d’uso in stile chat che sono principalmente server-to-client. Se stai già usando FrankenPHP, funziona senza alcuna infrastruttura aggiuntiva.
Pagine correlate
- Fondamenti del broadcasting
- Laravel Cloud (runtime basato su FrankenPHP)