Express.js
WebSockets, SSE y tiempo real
Compara polling, Server-Sent Events y WebSockets para tiempo real, incluyendo autenticación, escalado, brokers, backpressure y reconexión.
- Última actualización
- Actualizada
- Nivel
- Profundización
Express.js
Compara polling, Server-Sent Events y WebSockets para tiempo real, incluyendo autenticación, escalado, brokers, backpressure y reconexión.
Tiempo real no significa necesariamente WebSocket. La elección depende de dirección del flujo, frecuencia, reconexión, escalado y garantías de entrega.
HTTP tradicional funciona por request-response. Algunas interfaces necesitan recibir cambios sin preguntar constantemente.
Tres modelos comunes:
polling
→ cliente consulta periódicamente
SSE
→ servidor envía eventos sobre HTTP
WebSocket
→ canal bidireccional persistenteEl cliente ejecuta GET cada cierto tiempo. Es simple, compatible con infraestructura y fácil de cachear, pero introduce latencia y requests vacías.
Conviene cuando los cambios son poco frecuentes o el intervalo tolerable.
El servidor mantiene la request hasta que existe un evento o timeout. Reduce requests vacías, pero administra muchas requests largas y reconexiones.
SSE utiliza text/event-stream y flujo servidor→cliente.
app.get('/events', authenticate, (request, response) => {
response.status(200);
response.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
});
response.flushHeaders();
const unsubscribe = events.subscribe(response.locals.actor.id, (event) => {
response.write(`id: ${event.id}\n`);
response.write(`event: ${event.type}\n`);
response.write(`data: ${JSON.stringify(event.payload)}\n\n`);
});
request.on('close', unsubscribe);
});El navegador reconecta automáticamente con EventSource. Last-Event-ID puede ayudar a reanudar si conservas historial.
WebSocket cambia de HTTP a un protocolo full-duplex. Cliente y servidor pueden enviar mensajes en cualquier momento.
Express puede compartir el servidor HTTP con una librería WebSocket, pero Express no administra mensajes después del upgrade.
HTTP upgrade
↓
WebSocket connection
↓
frames bidireccionalesLa conexión debe autenticar al abrirse y revalidar permisos para cada operación sensible. Una sesión válida al conectar puede revocarse después.
Evita tokens en query strings porque aparecen en logs. Cookies o protocolos de autenticación explícitos tienen sus propios riesgos.
No basta con autenticar. Una conexión de tenant A no debe suscribirse a eventos de tenant B.
actor + tenant + channel + resource
→ policyValida cada suscripción y filtra eventos en servidor.
Con varias instancias, una conexión vive en una sola. Si un evento se produce en otra, necesitas un broker:
instance A publishes
↓ Redis/NATS/Kafka
instance B receives
↓
connected clientSticky sessions pueden ayudar a reconexión, pero no distribuyen eventos por sí solas.
Un cliente lento puede acumular mensajes. Define:
No guardes eventos infinitos en memoria por conexión.
WebSocket/SSE no garantizan por sí mismos entrega durable. Una conexión puede caer después de que el servidor envía y antes de que el cliente procesa.
Para operaciones críticas usa IDs, acknowledgements, replay o consulta del estado fuente. El tiempo real suele ser una notificación; la base de datos sigue siendo la verdad.
Proxies y NAT pueden cerrar conexiones inactivas. Usa ping/pong o comentarios SSE y timeouts.
Distingue conexión abierta de cliente saludable.
DomiSys muestra una nueva orden al administrador:
order.created.{ eventId, orderId }.Enviar solo identificador reduce payload y evita convertir el canal en otra fuente de verdad.
SSE: servidor→cliente, HTTP simple, reconexión integrada, texto, buena opción para notificaciones y progreso.
WebSocket: bidireccional, frames binarios/texto, útil para colaboración, chat o control interactivo; operación más compleja.
Polling: simple y robusto cuando la latencia no es crítica.
Al desplegar:
Clientes deben reconectar con backoff y jitter.
Health checks: liveness y readiness prepara el servicio para operación en una plataforma.