Visión general
La capa de broadcasting de Laravel ha ofrecido durante mucho tiempo Reverb, Pusher y Ably como drivers «nativos de WebSocket». Ahora se ha añadido un nuevo valormercure para el driver en config/broadcasting.php.
Mercure es un protocolo en tiempo real construido sobre Server-Sent Events (SSE) en lugar de una conexión WebSocket bidireccional. Se comporta más como long-polling sobre HTTP/1.1 o HTTP/2, lo que le da varias propiedades distintivas:
- Atraviesa la infraestructura HTTP habitual (reverse proxies, CDNs, balanceadores de carga) de forma transparente.
- Los clientes se pueden implementar únicamente con la API
EventSourcedel navegador — no hace falta ninguna librería cliente dedicada. - FrankenPHP incluye un hub Mercure integrado, así que no necesitas infraestructura adicional para probarlo.
El nuevo valor de driver
El comentario con los drivers soportados que aparece al principio de config/broadcasting.php ahora lista mercure:
url, el driver hace fallback al hub Mercure integrado de FrankenPHP (la función mercure_publish()). Esa decisión se toma en CreatesMercureDrivers::mercure():
url debe apuntar a la API de administración usada para publicar, mientras que public_url es la URL a la que se conecta el navegador. Separar ambos soporta configuraciones donde la publicación ocurre a través de una red interna (por ejemplo, Docker Compose) mientras que solo se expone la URL pública al navegador.
Tokens separados para publicación y suscripción
Mercure es un protocolo de control de acceso basado en JWT. El traitCreatesMercureDrivers construye fábricas de tokens separadas para publicar (servidor → hub) y suscribirse (navegador → hub):
secret,publish_secretysubscribe_secretse pueden configurar de forma independiente, con fallback asecret.algorithm,publish_algorithmysubscribe_algorithmtambién se pueden fijar por cada lado (por defectoHS256).- HS256 requiere un secret de al menos 32 bytes, HS384 al menos 48 y HS512 al menos 64; en caso contrario se lanza una
InvalidArgumentException.
Grant::ACTION_PUBLISH para todos los topics (*) y se memoiza mediante CachingTokenProvider, de modo que no se acuñe un JWT nuevo en cada llamada a broadcast.
Autorización de canales mediante una sola cookie
La mayor diferencia arquitectónica respecto a los drivers WebSocket es que la autorización del suscriptor se gestiona a través de una única cookie.MercureBroadcaster::auth() acepta un array channel_names (con un máximo de 100 por petición), evalúa la autorización por canal y luego emite una sola cookie de autorización que los cubre todos:
denied: true en el payload de la respuesta mientras que el resto de canales autorizados siguen funcionando. Esto importa porque Mercure multiplexa muchos topics sobre una sola conexión EventSource, de forma que se pueden añadir o quitar canales en mitad de la sesión sin necesidad de cortar la conexión.
Los canales de presence reciben una forma de Grant distinta a los canales private/private-encrypted normales, orientada al patrón de URL de suscripción usado por la Subscription API de Mercure.
Canales con cifrado de extremo a extremo
Los canales cuyo nombre empieza porprivate-encrypted- se tratan como canales cifrados de extremo a extremo (E2EE) — lo que significa que ni siquiera el propio hub de Mercure ve nunca el payload. Esta es una capacidad que los drivers existentes de Pusher y Reverb no ofrecen.
Configurar una encryption_key de 32 bytes codificada en base64 activa el ChannelEncrypter, que envuelve el nombre del evento, el payload y el socket ID en un JWE (JSON Web Encryption) antes de que broadcast() los envíe. El hub solo retransmite bytes cifrados.
jwk (JSON Web Key) devuelto por la respuesta de auth() — un intercambio de claves fuera de banda recomendado por la especificación de Mercure, de modo que el hub nunca llega a conocer la clave.
Los canales de presence no se pueden cifrar, ya que su lista de miembros circula por la Subscription API del hub por diseño — eso es incompatible con E2EE.
Whispers (mensajes directos entre clientes)
Cuandoclient_events está habilitado (por defecto), cada canal protegido recibe un «whisper topic» dedicado sobre el que los suscriptores pueden publicar:
Nomenclatura de topics
Como los hubs de Mercure suelen compartirse entre varias aplicaciones, los topics se agrupan bajo untopic_prefix para evitar colisiones. El valor por defecto es:
.alt es un sufijo DNS reservado y no resoluble (RFC 9476), así que nunca puede chocar con un dominio real. Los nombres de canal se codifican como URL según la RFC 3986 en un único segmento de ruta:
Dominio de la cookie y mensajes de error
Como un hub de Mercure a menudo se ejecuta en un subdominio distinto al de la aplicación (por ejemplo,mercure.example.com frente a app.example.com), un fallo al resolver un dominio de cookie compartido lanza una excepción descriptiva:
__Secure- o __Host-, el driver también verifica en el arranque que public_url sea HTTPS:
Cuándo elegir Reverb, Pusher/Ably o Mercure
Mercure encaja bien cuando no necesitas una conexión bidireccional persistente — notificaciones, actualizaciones de progreso o casos de uso tipo chat que son principalmente de servidor a cliente. Si ya estás ejecutando FrankenPHP, funciona sin ninguna infraestructura adicional.
Páginas relacionadas
- Fundamentos de broadcasting
- Laravel Cloud (runtime basado en FrankenPHP)