W3docs

API WebSocket de JavaScript

Aprende la API WebSocket de JavaScript: ciclo de vida de la conexión, readyState, envío de texto, JSON y datos binarios, reconexión y seguridad, con un ejemplo de Echo Chat ejecutable.

Introducción a la tecnología WebSocket

WebSocket es un protocolo que proporciona un canal de comunicación full-duplex (bidireccional) entre el navegador y un servidor a través de una única conexión TCP de larga duración. Una vez abierta la conexión, cualquiera de los dos extremos puede enviar un mensaje en cualquier momento sin esperar a que el otro lo solicite — algo que el HTTP convencional no puede hacer.

Esta página cubre qué problemas resuelven los WebSockets, el ciclo de vida de la conexión, el envío de texto y datos binarios, el trabajo con mensajes JSON, la reconexión, la seguridad y cuándo usar una biblioteca en lugar de la API nativa. Todo se construye en torno a un ejemplo de Echo Chat ejecutable.

¿Por qué WebSockets en lugar de HTTP?

Con HTTP convencional (incluidos la Fetch API y XMLHttpRequest), el cliente debe iniciar cada intercambio. Para obtener actualizaciones en tiempo real hay que hacer polling — preguntar repetidamente "¿hay algo nuevo?" — lo que desperdicia ancho de banda y añade latencia. Los WebSockets invierten esto: el servidor puede enviar datos en el instante en que los tiene, con prácticamente ninguna sobrecarga por mensaje.

EnfoqueDirecciónSobrecargaIdeal para
Petición/respuesta HTTPEl cliente pregunta, el servidor respondeCabeceras completas por peticiónSolicitudes puntuales, APIs REST
PollingEl cliente pregunta según un temporizadorMuchas peticiones innecesariasActualizaciones simples y poco frecuentes
WebSocketAmbos envían librementeUn handshake, frames pequeñosChat, feeds en vivo, juegos, dashboards

Usa WebSockets cuando el servidor necesite hablar primero o los mensajes fluyan constantemente: chat, juegos multijugador, editores colaborativos, tickers de bolsa y dashboards en tiempo real. Para actualizaciones ocasionales unidireccionales del servidor al cliente únicamente, los Server-Sent Events o la Push API pueden ser más sencillos.

El ciclo de vida de la conexión WebSocket

Abres una conexión pasando una URL ws:// (sin cifrar) o wss:// (cifrada) al constructor WebSocket. La conexión pasa entonces por cuatro estados expuestos por socket.readyState:

ConstanteValorSignificado
WebSocket.CONNECTING0Handshake en progreso (estado inicial)
WebSocket.OPEN1Listo para enviar y recibir
WebSocket.CLOSING2Se ha solicitado un cierre
WebSocket.CLOSED3Conexión cerrada o no se pudo abrir

Reaccionas a las transiciones con cuatro eventos: open, message, error y close. La regla clave es que solo puedes llamar a socket.send() mientras readyState sea OPEN — enviar antes de que se dispare open lanza un error.

const socket = new WebSocket("wss://echo.websocket.events");

socket.addEventListener("open", () => {
  console.log("open, readyState =", socket.readyState); // 1
  socket.send("hello");
});

socket.addEventListener("message", (event) => {
  console.log("received:", event.data); // "hello" (echoed back)
});

socket.addEventListener("close", (event) => {
  console.log("closed, code =", event.code); // e.g. 1000
});

Configuración del Echo Chat con WebSocket

Estructura HTML básica

Primero, establecemos la interfaz de usuario con HTML que incluye un área de visualización de mensajes, un campo de entrada y botones de control.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>WebSocket Echo Chat</title>
</head>
<body>
    <textarea id="chatBox" readonly style="width: 100%; height: 300px"></textarea><br />
    <input type="text" id="messageInput" placeholder="Type a message..." style="width: 75%" />
    <button onclick="sendMessage()">Send</button>
    <button onclick="closeConnection()">Close Connection</button>
</body>
</html>

Integración de WebSocket con JavaScript

El JavaScript para gestionar la comunicación WebSocket es clave para habilitar las interacciones en tiempo real.

<script>
    // Accessing the chat box and message input elements from the HTML.
    const chatBox = document.getElementById("chatBox");
    const messageInput = document.getElementById("messageInput");

    // Establishing a WebSocket connection to the echo server.
    const socket = new WebSocket("wss://echo.websocket.events");

    // When the connection is open, display a connected message in the chat box.
    socket.addEventListener("open", function (event) {
        chatBox.value += "Connected to the echo server\n";
    });

    // Handle incoming messages by adding them to the chat box.
    socket.addEventListener("message", function (event) {
        chatBox.value += "Echoed back: " + event.data + "\n";
    });

    // Handle connection errors.
    socket.addEventListener("error", function (event) {
        chatBox.value += "Connection error occurred.\n";
    });

    // Handle connection closure.
    socket.addEventListener("close", function (event) {
        chatBox.value += "Connection closed. Code: " + event.code + "\n";
    });

    // Function to send a message when the send button is clicked.
    function sendMessage() {
        const message = messageInput.value; // Get the message from the input field.
        if (!message) return; // If there's no message, don't do anything.
        socket.send(message); // Send the message to the server.
        chatBox.value += "You: " + message + "\n"; // Show the message in the chat box.
        messageInput.value = ""; // Clear the message input field.
    }

    // Function to close the WebSocket connection.
    function closeConnection() {
        if (socket.readyState === WebSocket.OPEN) {
            socket.close(1000, "The user closed the connection"); // Close the connection normally.
            chatBox.value += "Connection closed by user\n"; // Inform the user in the chat box.
        } else {
            alert("Connection is not open or already closed."); // Alert if the connection can't be closed.
        }
    }

    // Ensure the WebSocket is closed properly when the webpage is closed or reloaded.
    window.addEventListener("beforeunload", function () {
        if (socket.readyState === WebSocket.OPEN) {
            socket.close(1000, "The page is unloading"); // Close the connection normally.
        }
    });
</script>

Este script configura una función de chat en una página web que se conecta a un servidor mediante WebSockets. A continuación, una explicación sencilla de sus partes:

  1. Acceso a los elementos HTML: El script obtiene el cuadro de chat y el campo de entrada de mensajes de la página web para poder interactuar con ellos.
  2. Conexión WebSocket: Abre una conexión a un servidor que repite los mensajes de vuelta. Esto significa que cualquier cosa que envíes a este servidor te será devuelta inmediatamente.
  3. Mostrar el estado de la conexión: Cuando la conexión se establece con éxito, muestra un mensaje en el cuadro de chat indicando que la conexión al servidor de eco está establecida.
  4. Gestión de mensajes entrantes: Los mensajes que llegan del servidor se añaden al cuadro de chat, mostrando que el servidor ha devuelto los mensajes.
  5. Envío de mensajes: Hay una función para enviar los mensajes escritos en el campo de entrada. Si hay texto, lo envía al servidor y lo muestra en el cuadro de chat como tu mensaje.
  6. Cierre de la conexión: También hay una función para cerrar la conexión WebSocket cuando sea necesario, como cuando el usuario decide cerrarla o cuando la página web se está cerrando.

Esta configuración permite la comunicación en tiempo real con el servidor y ayuda a probar y demostrar cómo funcionan las aplicaciones de mensajería.

Ahora juntemos todo y veámoslo en acción:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>WebSocket Echo Chat</title>
  </head>

  <body>
    <textarea id="chatBox" readonly style="width: 100%; height: 300px">
    </textarea>
    <br />
    <input
      type="text"
      id="messageInput"
      placeholder="Type a message..."
      style="width: 75%"
    />
    <button onclick="sendMessage()">Send</button>
    <button onclick="closeConnection()">Close Connection</button>
  </body>
  <script>
    const chatBox = document.getElementById("chatBox");
    const messageInput = document.getElementById("messageInput");

    const socket = new WebSocket("wss://echo.websocket.events");

    socket.addEventListener("open", function (event) {
      chatBox.value += "Connected to the echo server\n";
    });

    socket.addEventListener("message", function (event) {
      chatBox.value += "Echoed back: " + event.data + "\n";
    });

    socket.addEventListener("error", function (event) {
      chatBox.value += "Connection error occurred.\n";
    });

    socket.addEventListener("close", function (event) {
      chatBox.value += "Connection closed. Code: " + event.code + "\n";
    });

    function sendMessage() {
      const message = messageInput.value;
      if (!message) return;
      socket.send(message);
      chatBox.value += "You: " + message + "\n";
      messageInput.value = "";
    }

    function closeConnection() {
      if (socket.readyState === WebSocket.OPEN) {
        socket.close(1000, "The user closed the connection");
        chatBox.value += "Connection closed by user\n";
      } else {
        alert("Connection not open or already closed.");
      }
    }

    window.addEventListener("beforeunload", function () {
      if (socket.readyState === WebSocket.OPEN) {
        socket.close(1000, "The page is unloading");
      }
    });
  </script>
</html>

En el ejemplo anterior, en cuanto te conectas al servidor, puedes empezar a enviar mensajes y recibirás exactamente lo que has escrito, devuelto en eco. Si haces clic en el botón 'Close Connection', la conexión WebSocket se terminará y ya no recibirás mensajes de eco.

Características y técnicas avanzadas de WebSocket

Envío de datos estructurados como JSON

Las aplicaciones reales rara vez envían cadenas simples — envían objetos. Como el canal solo transporta texto o datos binarios, serializas los objetos con JSON.stringify() antes de enviarlos y los vuelves a analizar con JSON.parse() al recibirlos. Consulta Trabajar con JSON para más información sobre este formato.

// Sending an object
const payload = { type: "chat", user: "Ann", text: "Hi!" };
socket.send(JSON.stringify(payload));

// Receiving and parsing it
socket.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);
  console.log(msg.user + ": " + msg.text); // "Ann: Hi!"
});

Un patrón común es un campo type que permite que una conexión multiplexa muchos tipos de mensajes — chat, presence, typing, etc. — cada uno gestionado por su propia rama.

Gestión de datos binarios

Los WebSockets no se limitan al texto. También pueden transportar frames binarios, útiles para audio, imágenes o estado de juego. Establece socket.binaryType para controlar cómo llegan los datos binarios entrantes — "blob" (el valor predeterminado) o "arraybuffer".

socket.binaryType = "arraybuffer";

// Send raw bytes
const bytes = new Uint8Array([72, 73]); // "HI"
socket.send(bytes);

socket.addEventListener("message", (event) => {
  if (typeof event.data === "string") {
    console.log("text frame:", event.data);
  } else {
    const view = new Uint8Array(event.data);
    console.log("binary frame, length:", view.length);
  }
});

Reconexión automática

Las redes fallan. El WebSocket nativo no se reconecta por sí solo — cuando el evento close se dispara de forma inesperada, debes reabrir la conexión manualmente, idealmente con un retroceso creciente (exponencial) para no saturar el servidor.

let delay = 1000; // start at 1 second

function connect() {
  const socket = new WebSocket("wss://echo.websocket.events");

  socket.addEventListener("open", () => {
    delay = 1000; // reset back-off after a successful connection
  });

  socket.addEventListener("close", () => {
    setTimeout(connect, delay);
    delay = Math.min(delay * 2, 30000); // cap at 30 seconds
  });
}

connect();

Implementación de la seguridad en WebSocket

La seguridad es fundamental cuando se trabaja con WebSockets:

  • Usa WSS: Utiliza siempre WebSocket Secure (WSS), que cifra los datos transmitidos entre el cliente y el servidor.
  • Autenticación: Implementa autenticación basada en tokens para garantizar que solo los usuarios autorizados puedan establecer conexiones WebSocket.
  • Validación: Valida correctamente todos los datos enviados al servidor para prevenir vulnerabilidades web comunes como XSS o inyección SQL.

WebSocket y el patrón Pub/Sub

El patrón publicación/suscripción es un modelo popular en los servicios de datos en tiempo real donde los mensajes se difunden a través de un canal. Los servicios WebSocket como PubNub ofrecen APIs que soportan el modelo pub/sub, mejorando las capacidades de WebSocket mediante la gestión de conexiones, el cifrado de datos y la difusión basada en canales.

Bibliotecas y frameworks de WebSocket

Varias bibliotecas JavaScript facilitan el trabajo con WebSockets y lo hacen más robusto:

  • Socket.IO: Proporciona características adicionales como reconexión automática, gestión de eventos y manejo de salas.
  • WebSocket-Node: Una implementación de servidor WebSocket para Node.js.
  • ReconnectingWebSocket: Una pequeña biblioteca que añade funciones de reconexión a los WebSockets nativos.

Conclusión

La tecnología WebSocket es un bloque fundamental para desarrollar aplicaciones web interactivas y en tiempo real. Al integrar WebSockets en tus aplicaciones, habilitas la interacción directa y bidireccional entre clientes y servidores. Esta guía recorrió el ciclo de vida de la conexión, el ejemplo de Echo Chat, los mensajes JSON y binarios, la reconexión y la seguridad — suficiente para construir características robustas en tiempo real.

Ver también

  • Fetch API — para peticiones HTTP puntuales cuando no necesitas un canal en vivo.
  • XMLHttpRequest — la API de peticiones anterior sobre la que WebSockets y Fetch se basan conceptualmente.
  • Push API — mensajes del servidor al cliente incluso cuando la página está cerrada.
  • Trabajar con JSON — el formato estándar para mensajes WebSocket estructurados.

Práctica

Práctica
¿Cuáles son las principales ventajas de usar WebSockets en aplicaciones web?
¿Cuáles son las principales ventajas de usar WebSockets en aplicaciones web?
Práctica
¿En qué readyState puedes llamar a socket.send() de forma segura?
¿En qué readyState puedes llamar a socket.send() de forma segura?
Práctica
¿Cómo se envía un object de JavaScript a través de un WebSocket?
¿Cómo se envía un object de JavaScript a través de un WebSocket?
Was this page helpful?