W3docs

JavaScript WebSocket API

Impara la JavaScript WebSocket API: ciclo di vita della connessione, readyState, invio di dati testo, JSON e binari, riconnessione e sicurezza, con un esempio di Echo Chat eseguibile.

Introduzione alla Tecnologia WebSocket

WebSocket è un protocollo che fornisce un canale di comunicazione full-duplex (bidirezionale) tra il browser e un server su un'unica connessione TCP persistente. Una volta aperta la connessione, entrambe le parti possono inviare un messaggio in qualsiasi momento senza dover aspettare che l'altra lo richieda — qualcosa che il semplice HTTP non può fare.

Questa pagina illustra cosa risolvono i WebSocket, il ciclo di vita della connessione, l'invio di dati testo e binari, la gestione dei messaggi JSON, la riconnessione, la sicurezza e quando conviene usare una libreria al posto dell'API nativa. Tutto viene costruito attorno a un esempio di Echo Chat eseguibile.

Perché WebSocket invece di HTTP?

Con il normale HTTP (incluse la Fetch API e XMLHttpRequest), il client deve iniziare ogni scambio. Per ricevere aggiornamenti in tempo reale si deve ricorrere al polling — chiedere ripetutamente "ci sono novità?" — il che spreca larghezza di banda e aumenta la latenza. I WebSocket ribaltano questo schema: il server può inviare dati nel momento esatto in cui li ha, con un overhead per messaggio quasi nullo.

ApproccioDirezioneOverheadIdeale per
Richiesta/risposta HTTPIl client chiede, il server rispondeHeader completi per ogni richiestaRichieste singole, REST API
PollingIl client chiede a intervalli regolariMolte richieste inutiliAggiornamenti semplici a bassa frequenza
WebSocketEntrambi inviano liberamenteUn solo handshake, frame minimaliChat, feed live, giochi, dashboard

Usa i WebSocket quando il server deve parlare per primo o i messaggi scorrono continuamente: chat, giochi multiplayer, editor collaborativi, ticker di trading e dashboard in tempo reale. Per aggiornamenti occasionali unidirezionali dal server al client, Server-Sent Events o la Push API possono essere più semplici.

Il Ciclo di Vita della Connessione WebSocket

Si apre una connessione passando un URL ws:// (non cifrato) o wss:// (cifrato) al costruttore WebSocket. La connessione attraversa poi quattro stati esposti da socket.readyState:

CostanteValoreSignificato
WebSocket.CONNECTING0Handshake in corso (stato iniziale)
WebSocket.OPEN1Pronto per inviare e ricevere
WebSocket.CLOSING2È stata richiesta la chiusura
WebSocket.CLOSED3Connessione chiusa o apertura fallita

Alle transizioni si reagisce con quattro eventi: open, message, error e close. La regola fondamentale è che si può chiamare socket.send() solo quando readyState è OPEN — inviare prima che scatti open genera un errore.

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
});

Configurazione dell'Echo Chat WebSocket

Struttura HTML di Base

Prima di tutto, definiamo l'interfaccia utente in HTML: un'area di visualizzazione dei messaggi, un campo di input e i pulsanti di controllo.

<!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>

Integrazione di WebSocket con JavaScript

Il JavaScript per la gestione della comunicazione WebSocket è fondamentale per abilitare le interazioni in tempo reale.

<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>

Questo script configura una funzionalità di chat su una pagina web che si connette a un server tramite WebSocket. Ecco una spiegazione semplice delle sue parti:

  1. Accesso agli elementi HTML: Lo script recupera dalla pagina il box della chat e il campo di input dei messaggi per poter interagire con essi.
  2. Connessione WebSocket: Apre una connessione verso un server che rimanda indietro i messaggi. Ciò significa che tutto ciò che invii a questo server ti verrà restituito immediatamente.
  3. Visualizzazione dello stato della connessione: Quando la connessione viene stabilita con successo, nel box della chat appare un messaggio che conferma la connessione all'echo server.
  4. Gestione dei messaggi in arrivo: I messaggi che arrivano dal server vengono aggiunti al box della chat, mostrando che il server ha rimandato indietro i messaggi.
  5. Invio dei messaggi: È presente una funzione per inviare i messaggi digitati nel campo di input. Se c'è del testo, lo invia al server e lo visualizza nel box della chat come messaggio dell'utente.
  6. Chiusura della connessione: È presente anche una funzione per chiudere la connessione WebSocket quando necessario, ad esempio quando l'utente decide di chiuderla o quando la pagina viene chiusa.

Questa configurazione consente la comunicazione in tempo reale con il server e aiuta a testare e dimostrare come funzionano le applicazioni di messaggistica.

Ora mettiamo tutto insieme e vediamolo in azione:

<!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>

Nell'esempio sopra, non appena ci si connette al server, si possono iniziare a inviare messaggi e si riceverà esattamente ciò che si è digitato, rimandato indietro. Se si fa clic sul pulsante 'Close Connection', la connessione WebSocket verrà terminata e non si riceveranno più messaggi in eco.

Funzionalità e Tecniche WebSocket Avanzate

Invio di Dati Strutturati come JSON

Le applicazioni reali raramente inviano stringhe semplici — inviano object. Poiché il canale trasmette solo testo o dati binari, è necessario serializzare gli object con JSON.stringify() prima di inviarli e riconvertirli con JSON.parse() alla ricezione. Consulta Lavorare con JSON per maggiori dettagli su questo 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 pattern comune è un campo type che permette a una singola connessione di gestire molti tipi di messaggi — chat, presence, typing e così via — ciascuno gestito dal proprio ramo di codice.

Gestione dei Dati Binari

I WebSocket non si limitano al testo. Possono anche trasportare frame binari, utili per audio, immagini o stato di gioco. Imposta socket.binaryType per controllare come arrivano i dati binari in entrata — "blob" (il valore predefinito) 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);
  }
});

Riconnessione Automatica

Le reti cadono. Il WebSocket nativo non si riconnette da solo — quando close scatta inaspettatamente, bisogna riaprire la connessione manualmente, idealmente con un back-off crescente (esponenziale) per non sovraccaricare il server.

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();

Implementare la Sicurezza WebSocket

La sicurezza è fondamentale quando si lavora con i WebSocket:

  • Usare WSS: Utilizzare sempre WebSocket Secure (WSS), che cifra i dati trasmessi tra client e server.
  • Autenticazione: Implementare l'autenticazione basata su token per garantire che solo gli utenti autorizzati possano stabilire connessioni WebSocket.
  • Validazione: Validare correttamente tutti i dati inviati al server per prevenire vulnerabilità web comuni come XSS o SQL injection.

WebSocket e Pattern Pub/Sub

Il pattern publish/subscribe è un modello diffuso nei servizi dati in tempo reale in cui i messaggi vengono trasmessi attraverso un canale. Servizi WebSocket come PubNub offrono API che supportano il modello pub/sub, potenziando le capacità dei WebSocket attraverso la gestione delle connessioni, la cifratura dei dati e la trasmissione basata su canali.

Librerie e Framework per WebSocket

Diverse librerie JavaScript rendono più semplice e robusto il lavoro con i WebSocket:

  • Socket.IO: Fornisce funzionalità aggiuntive come la riconnessione automatica, la gestione degli eventi e la gestione delle stanze.
  • WebSocket-Node: Un'implementazione di server WebSocket per Node.js.
  • ReconnectingWebSocket: Una piccola libreria che aggiunge funzionalità di riconnessione ai WebSocket nativi.

Conclusione

La tecnologia WebSocket è un componente fondamentale per lo sviluppo di applicazioni web interattive e in tempo reale. Integrando i WebSocket nelle tue applicazioni, abiliti un'interazione diretta e bidirezionale tra client e server. Questa guida ha illustrato il ciclo di vita della connessione, l'esempio Echo Chat, i messaggi JSON e binari, la riconnessione e la sicurezza — tutto il necessario per costruire funzionalità in tempo reale robuste.

Vedi Anche

  • Fetch API — per richieste HTTP singole quando non si ha bisogno di un canale live.
  • XMLHttpRequest — la vecchia API di richiesta su cui WebSocket e Fetch si basano concettualmente.
  • Push API — messaggi dal server al client anche quando la pagina è chiusa.
  • Lavorare con JSON — il formato standard per i messaggi WebSocket strutturati.

Esercitazione

Pratica
Quali sono i principali vantaggi dell'uso dei WebSocket nelle applicazioni web?
Quali sono i principali vantaggi dell'uso dei WebSocket nelle applicazioni web?
Pratica
In quale readyState puoi chiamare socket.send() in modo sicuro?
In quale readyState puoi chiamare socket.send() in modo sicuro?
Pratica
Come si invia un object JavaScript tramite un WebSocket?
Come si invia un object JavaScript tramite un WebSocket?
Was this page helpful?