Vue d’ensemble
La couche broadcasting de Laravel a longtemps proposé Reverb, Pusher et Ably comme drivers « WebSocket natifs ». Une nouvelle valeurmercure vient d’être ajoutée à config/broadcasting.php.
Mercure est un protocole temps réel bâti sur Server-Sent Events (SSE) plutôt que sur une connexion WebSocket bidirectionnelle. Il se comporte davantage comme du long-polling HTTP/1.1 ou HTTP/2, ce qui lui confère plusieurs propriétés distinctes :
- Il traverse de manière transparente l’infrastructure HTTP habituelle (reverse proxies, CDN, load balancers).
- Les clients peuvent être implémentés uniquement avec l’API
EventSourcedu navigateur — aucune bibliothèque cliente dédiée n’est nécessaire. - FrankenPHP embarque un hub Mercure intégré, donc aucune infrastructure supplémentaire n’est requise pour l’essayer.
La nouvelle valeur driver
Le commentaire listant les drivers supportés en tête de config/broadcasting.php mentionne désormais mercure :
url est omis, le driver bascule automatiquement sur le hub Mercure intégré à FrankenPHP (la fonction mercure_publish()). Cette décision est prise dans CreatesMercureDrivers::mercure() :
url doit pointer vers l’API d’administration utilisée pour la publication, tandis que public_url correspond à l’URL à laquelle le navigateur se connecte. Cette séparation permet des configurations où la publication passe par un réseau interne (par exemple Docker Compose) alors que seule l’URL publique est exposée au navigateur.
Tokens de publication et d’abonnement séparés
Mercure est un protocole de contrôle d’accès basé sur JWT. Le traitCreatesMercureDrivers construit deux fabriques de tokens distinctes : l’une pour la publication (serveur → hub), l’autre pour l’abonnement (navigateur → hub) :
secret,publish_secretetsubscribe_secretpeuvent chacun être configurés indépendamment, avec un repli sursecret.algorithm,publish_algorithmetsubscribe_algorithmpeuvent de la même façon être définis par côté (valeur par défautHS256).- HS256 exige un secret d’au moins 32 octets, HS384 au moins 48 et HS512 au moins 64 ; dans le cas contraire, une
InvalidArgumentExceptionest levée.
Grant::ACTION_PUBLISH pour tous les topics (*) et est mémoïsé par CachingTokenProvider, afin de ne pas régénérer un nouveau JWT à chaque appel de broadcast.
Autorisation de canal via un cookie unique
La plus grande différence architecturale par rapport aux drivers WebSocket est que l’autorisation côté abonné est gérée par un seul cookie.MercureBroadcaster::auth() accepte un tableau channel_names (plafonné à 100 par requête), évalue l’autorisation canal par canal, puis émet un unique cookie d’autorisation qui les couvre tous :
denied: true dans la charge utile pendant que les autres canaux autorisés continuent de fonctionner. Cela compte parce que Mercure multiplexe de nombreux topics sur une seule connexion EventSource : les canaux peuvent donc être ajoutés ou retirés en cours de session sans détruire la connexion.
Les canaux Presence reçoivent une forme de Grant différente de celle des canaux private/private-encrypted classiques, ciblant le pattern d’URL d’abonnement utilisé par l’API Subscription de Mercure.
Canaux chiffrés de bout en bout
Les canaux préfixés parprivate-encrypted- sont traités comme chiffrés de bout en bout (E2EE) — ce qui signifie que même le hub Mercure lui-même ne voit jamais la charge utile. Cette capacité n’existe pas dans les drivers Pusher et Reverb actuels.
Définir une encryption_key de 32 octets encodée en base64 active le ChannelEncrypter, qui empaquette le nom de l’événement, la charge utile et le socket ID dans un JWE (JSON Web Encryption) avant l’envoi par broadcast(). Le hub ne relaie donc que des octets chiffrés.
jwk (JSON Web Key) renvoyé dans la réponse de auth() — un échange de clé hors bande recommandé par la spécification Mercure, de sorte que le hub n’apprend jamais la clé.
Les canaux Presence ne peuvent pas être chiffrés, puisque leur liste de membres transite par conception via l’API Subscription du hub — ce qui est incompatible avec l’E2EE.
Whispers (messages directs entre clients)
Lorsqueclient_events est activé (valeur par défaut), chaque canal protégé se voit attribuer un « topic whisper » dédié auquel les abonnés peuvent publier :
Nommage des topics
Comme les hubs Mercure sont souvent partagés entre plusieurs applications, les topics sont placés sous un espace de nomstopic_prefix afin d’éviter les collisions. La valeur par défaut est :
.alt est un suffixe DNS réservé et non résolvable (RFC 9476), il ne peut donc jamais entrer en collision avec un domaine réel. Les noms de canaux sont encodés URL selon la RFC 3986 dans un unique segment de chemin :
Domaine de cookie et messages d’erreur
Un hub Mercure tourne fréquemment sur un sous-domaine différent de celui de l’application (par exemplemercure.example.com vs app.example.com) ; l’échec à résoudre un domaine de cookie commun lève donc une exception descriptive :
__Secure- ou __Host-, le driver vérifie également au démarrage que public_url est bien en HTTPS :
Choisir entre Reverb, Pusher/Ably et Mercure
Mercure convient bien lorsque vous n’avez pas besoin d’une connexion bidirectionnelle persistante — notifications, indicateurs de progression ou cas d’usage de type chat, essentiellement du serveur vers le client. Si vous utilisez déjà FrankenPHP, il fonctionne sans aucune infrastructure supplémentaire.
Pages liées
- Bases du broadcasting
- Laravel Cloud (runtime basé sur FrankenPHP)