Il protocollo HTTP tradizionale segue un modello rigido di "richiesta-risposta": il client invia un'istanza, il server risponde e la connessione si chiude. Questo paradigma è perfetto per la navigazione web statica, ma diventa un collo di bottiglia per applicazioni dinamiche come piattaforme di trading, chat live, dashboard IoT o giochi multiplayer. I WebSockets superano questo limite stabilendo un tunnel di comunicazione full-duplex e persistente, permettendo uno scambio di dati istantaneo senza overhead eccessivo.
Come Funzionano i WebSockets
Tutto ha inizio con un "handshake" basato su HTTP. Il client invia un header Upgrade: websocket, chiedendo al server di passare a una connessione WebSocket dedicata. Se il server accetta, risponde con lo stato 101 Switching Protocols. Da quel momento, il canale resta aperto, consentendo a entrambe le parti di scambiarsi pacchetti di dati in modo asincrono, evitando di rinegoziare continuamente gli header HTTP.
Client → Server: GET /chat HTTP/1.1 Host: esempio.it Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 Server → Client: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Confronto Tecnico: HTTP vs WebSockets
- HTTP: Basato su richiesta del client, stateless, richiede l'invio di header pesanti a ogni singola richiesta, ideale per REST API.
- WebSocket: Connessione persistente, bidirezionale, stateful, con un overhead di framing ridotto al minimo (circa 2-14 byte).
- SSE (Server-Sent Events): Ottimo per flussi di dati unidirezionali dal server al client, costruito direttamente sopra il protocollo HTTP standard.
Implementazione Lato Client
const ws = new WebSocket("wss://api.esempio.it/ws");
// Apertura canale
ws.addEventListener("open", () => {
console.log("Connessione stabilita!");
ws.send(JSON.stringify({ azione: "entra", stanza: "generale" }));
});
// Ricezione dati
ws.addEventListener("message", (event) => {
const data = JSON.parse(event.data);
console.log("Dati ricevuti:", data);
});
// Chiusura connessione
ws.addEventListener("close", (event) => {
console.log(`Disconnesso: ${event.code}`);
});
// Gestione errori
ws.addEventListener("error", (error) => {
console.error("Errore WebSocket:", error);
});
Server Node.js con la libreria ws
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws) => {
console.log("Nuovo client connesso");
ws.on("message", (message) => {
const data = JSON.parse(message);
// Broadcast verso tutti gli utenti connessi
wss.clients.forEach((client) => {
if (client.readyState === 1) {
client.send(JSON.stringify({
tipo: "notifica",
contenuto: data.text,
time: new Date().getTime()
}));
}
});
});
ws.on("close", () => {
console.log("Client scollegato");
});
});
Quando integrare i WebSockets
- ✅ Ideali per: Applicazioni di messaggistica, sistemi di notifica in tempo reale, editing collaborativo, trading in tempo reale, statistiche sportive live e monitoraggio dispositivi IoT.
- ❌ Evitare per: Operazioni CRUD standard, download di file, aggiornamenti sporadici (dove il polling o SSE sono più semplici e performanti).
Considerazioni per la Produzione
- Logica di Riconnessione: Le connessioni possono interrompersi. Implementa sempre un sistema di "exponential backoff" per tentare la riconnessione automatica.
- Heartbeats (Ping/Pong): Invia pacchetti di controllo periodici per verificare che il client sia ancora attivo e liberare le risorse server bloccate.
- Autenticazione: Non affidarti esclusivamente ai cookie. Invia token JWT tramite URL o nel primo messaggio di handshake per garantire sicurezza.
- Scalabilità Orizzontale: Poiché i WebSockets sono stateful, usa sistemi Pub/Sub come Redis o NATS per sincronizzare i messaggi tra più istanze del tuo server.
- Load Balancer: Assicurati che il tuo bilanciatore di carico supporti l'upgrade del protocollo e le sessioni persistenti.
Prova i Nostri Tool per Sviluppatori
Ottimizza, formatta e valida il tuo codice in un click.