Skip to main content
Il MercureBroadcaster di cui parla questa pagina è stato aggiunto nella PR #61474 di laravel/framework (mergiata il 10 settembre 2026). Al momento della scrittura non fa ancora parte di una release taggata e non è documentato sul sito ufficiale. Questa pagina è un’anteprima basata sul codice sorgente e sui docblock — consulta il changelog di laravel/framework prima di affidartici in produzione.

Panoramica

Il livello di broadcasting di Laravel ha da tempo offerto Reverb, Pusher e Ably come driver “WebSocket-native”. Ora è stato aggiunto un nuovo valore mercure 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 EventSource del 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:
È fornita anche una configurazione di connessione di esempio:
Se url viene omesso, il driver ricade sull’hub Mercure integrato di FrankenPHP (la funzione mercure_publish()). Questa decisione avviene in CreatesMercureDrivers::mercure():
Quando gestisci un hub esterno, 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 trait CreatesMercureDrivers costruisce factory di token separate per la pubblicazione (server → hub) e la sottoscrizione (browser → hub):
  • secret, publish_secret e subscribe_secret possono essere configurati in modo indipendente, con fallback su secret.
  • Allo stesso modo algorithm, publish_algorithm e subscribe_algorithm possono essere impostati per ogni lato (default HS256).
  • HS256 richiede un secret di almeno 32 byte, HS384 almeno 48 e HS512 almeno 64; in caso contrario viene sollevata una InvalidArgumentException.
Il token di pubblicazione porta Grant::ACTION_PUBLISH per ogni topic (*) ed è memoizzato da CachingTokenProvider, così non viene generato un nuovo JWT a ogni singola chiamata di broadcast. 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:
Un dettaglio importante: un singolo canale rifiutato non fa fallire l’intera risposta — viene marcato come 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 prefisso private-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.
I sottoscrittori decifrano nel browser usando il campo 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)

Quando client_events è abilitato (impostazione predefinita), a ogni canale protetto viene assegnato un “topic whisper” dedicato su cui i sottoscrittori possono pubblicare:
Il topic vero e proprio del canale rimane server-only, così un client non può mai falsificare un evento originato dal server. Questo rispecchia la funzionalità “client events” di Pusher, ma tiene l’autorizzazione ben separata usando topic distinti.

Convenzioni di naming dei topic

Poiché gli hub Mercure sono spesso condivisi tra più applicazioni, i topic vengono inseriti in un namespace tramite un topic_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:
Dato che un hub Mercure spesso gira su un sottodominio diverso da quello dell’applicazione (per esempio mercure.example.com contro app.example.com), un fallimento nella risoluzione di un dominio cookie condiviso solleva un’eccezione descrittiva:
Se usi un nome di cookie con prefisso __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

Ultima modifica il 13 settembre 2026