WebSocket en Node.js: servidor, cliente, heartbeat y reconexión

WebSocket en Node.js: servidor ws, cliente nativo, heartbeat | We.Inc

Crea un servidor WebSocket en Node.js con el paquete ws, conéctate con el cliente WebSocket nativo de Node, detecta sockets muertos con ping y pong y reconecta con backoff.

Node.js no tiene un servidor WebSocket integrado, así que la mayoría de proyectos instalan el paquete ws y crean un WebSocketServer. Para el lado del cliente, Node incluye un WebSocket global compatible con el del navegador, añadido en v21.0.0 y v20.10.0, sin flag desde v22.0.0 y marcado como estable en v22.4.0. Añade un heartbeat con ping y pong y la reconexión con backoff antes de pasar a producción.

Qué pieza hace qué

Esta guía construye un pequeño servidor tipo chat y los clientes que hablan con él, en orden: un servidor que hace eco y difunde mensajes, un script de Node que se conecta sin ninguna dependencia, un heartbeat que descarta las conexiones que murieron en silencio y un cliente que vuelve después de que el servidor se reinicie. La calculadora de abajo muestra cómo crecen tus tiempos de reintento antes de ponerlos en código.

Preguntas frecuentes

¿Node.js tiene WebSocket integrado?

Solo el cliente. La clase global WebSocket apareció en v21.0.0 y v20.10.0 tras el flag --experimental-websocket, perdió el flag en v22.0.0 y dejó de ser experimental en v22.4.0. Sigue sin haber un servidor integrado, por eso ws sigue siendo la opción habitual.

¿Uso ws o Socket.IO?

ws habla el protocolo WebSocket puro, así que cualquier cliente estándar puede conectarse, incluidos el navegador y el global de Node. Socket.IO añade su propio protocolo encima, con salas y reconexión automática, pero necesita su propia librería de cliente en el otro extremo.

¿Por qué mueren las conexiones sin un evento close?

Si una ruta de red desaparece, por ejemplo al cerrar la tapa de un portátil, nunca se envía un frame de cierre y el servidor se queda con un socket medio abierto. El heartbeat los encuentra: un socket que no respondió al último ping se termina en la siguiente ronda.

¿Puede un cliente de navegador enviar pings?

No. La API del navegador solo tiene send() y close(). Los navegadores sí responden por su cuenta con pongs a los pings del servidor, por eso el heartbeat del lado del servidor también funciona con clientes de navegador.

¿Cómo comparto un puerto con un servidor HTTP?

Crea tú mismo el servidor HTTP, por ejemplo con Express o node:http, y pásalo como new WebSocketServer({ server }). Las peticiones de upgrade van a ws y las peticiones normales a tu aplicación.

Cómo empieza una conexión

Los heartbeats, en palabras sencillas

Reconectar sin machacar el servidor

Paso 1: un servidor con ws

server.js: eco y difusión

Cada mensaje se reenvía a todos los clientes abiertos. El listener de error evita que un socket defectuoso tumbe el proceso.

Paso 2: un cliente sin dependencias

client.js: el WebSocket global de Node

Funciona sin cambios en Node 22 o posterior y en la consola de un navegador, porque ambos exponen la misma clase WebSocket.

Paso 3: descarta conexiones muertas con ping y pong

Nuestra versión del patrón del README de ws: marca como vivo al recibir un pong y termina todo lo que se saltó la última ronda.

Paso 4: un cliente que reconecta

reconnect.js: backoff exponencial con jitter

La espera se duplica tras cada intento fallido hasta un tope, recibe una variación aleatoria y se reinicia cuando se abre una conexión.

Detrás de nginx

nginx solo deja pasar el upgrade cuando reenvías tú mismo las cabeceras Upgrade y Connection. Antes de nginx 1.29.7 también necesitas proxy_http_version 1.1.

location de nginx para el socket

proxy_read_timeout sube el límite de inactividad de 60 segundos; de todos modos, el heartbeat de arriba mantiene el tráfico en marcha.

Calculadora de espera de reconexión

Define una primera espera, un multiplicador y un tope para ver cuánto espera un cliente antes de cada reintento, y la espera más corta y más larga al añadir jitter.

Primera espera (ms)

Multiplicador

Tope (ms)

Intentos a mostrar

Añadir jitter (esperar entre la mitad y la espera completa)

Espera antes de cada intento de reconexión

Intento

Espera

Con jitter

Total esperado hasta ahora

{n} a {v} s

Los mismos ajustes como código

Empieza gratis · Sin tarjeta de crédito

Relacionado: Guías

Producto

Para quién es

Funciones

Recursos

Empresa

Mapa del sitio