Skip to main content
El MercureBroadcaster que se explica aquí se añadió en el PR #61474 de laravel/framework (mergeado el 10 de septiembre de 2026). En el momento de escribir esto todavía no forma parte de una release etiquetada y no está documentado en el sitio de documentación oficial. Esta página es una vista previa basada en el código fuente y los docblocks — revisa el changelog de laravel/framework antes de depender de él en producción.

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 valor mercure 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 EventSource del 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:
También se incluye una configuración de conexión de ejemplo:
Si omites url, el driver hace fallback al hub Mercure integrado de FrankenPHP (la función mercure_publish()). Esa decisión se toma en CreatesMercureDrivers::mercure():
Cuando ejecutas un hub externo, 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 trait CreatesMercureDrivers construye fábricas de tokens separadas para publicar (servidor → hub) y suscribirse (navegador → hub):
  • secret, publish_secret y subscribe_secret se pueden configurar de forma independiente, con fallback a secret.
  • algorithm, publish_algorithm y subscribe_algorithm también se pueden fijar por cada lado (por defecto HS256).
  • 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.
El token de publicación lleva 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. 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:
Lo importante es que un único canal denegado no hace fallar toda la respuesta — se marca como 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 por private-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.
Los suscriptores descifran en el navegador usando el campo 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)

Cuando client_events está habilitado (por defecto), cada canal protegido recibe un «whisper topic» dedicado sobre el que los suscriptores pueden publicar:
El topic propio del canal se mantiene como server-only, de manera que un cliente nunca puede falsificar un evento originado en el servidor. Esto refleja la funcionalidad de «client events» de Pusher, pero mantiene la autorización claramente separada usando topics distintos.

Nomenclatura de topics

Como los hubs de Mercure suelen compartirse entre varias aplicaciones, los topics se agrupan bajo un topic_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:
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:
Si usas un nombre de cookie con prefijo __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

Última modificación el 13 de septiembre de 2026