WebSocket est un protocole de communication qui ouvre un canal bidirectionnel persistant entre client et serveur sur une seule connexion TCP. Contrairement à HTTP (requête → réponse), les deux parties peuvent envoyer des données à tout moment.

WebSocket démarre par une requête HTTP (upgrade), puis bascule sur son propre protocole. Voir Requêtes HTTP et HTTPS pour le contexte HTTP.


Le problème que WebSocket résout

HTTP classique (requête/réponse) :
  Client ──► GET /messages       ← le client doit demander
  Client ◄── 200 [données]
  ... 5 secondes plus tard ...
  Client ──► GET /messages       ← polling : inefficace
  Client ◄── 200 [rien de nouveau]

WebSocket (canal persistant) :
  Client ──► Handshake HTTP → upgrade WebSocket
  ════ Canal TCP persistant ouvert ════════════════
  Serveur ──► {"event": "new_message", "text": "Salut"} ← push immédiat
  Client  ──► {"event": "typing", "user": "Alice"}      ← push immédiat
  Serveur ──► {"event": "new_message", "text": "..."}

Handshake — ouverture de la connexion

La connexion WebSocket commence par une requête HTTP spéciale :

1. Requête HTTP du client (Upgrade) :
   GET /ws HTTP/1.1
   Host: api.exemple.com
   Upgrade: websocket
   Connection: Upgrade
   Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
   Sec-WebSocket-Version: 13

2. Réponse du serveur (101 Switching Protocols) :
   HTTP/1.1 101 Switching Protocols
   Upgrade: websocket
   Connection: Upgrade
   Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

3. La connexion TCP reste ouverte → plus de HTTP, protocole WS

Le code 101 Switching Protocols est la réponse HTTP qui “upgrade” la connexion.


Cycle de vie d’une connexion WebSocket

Client                               Serveur
  │── HTTP Upgrade ────────────────► │
  │◄── 101 Switching Protocols ────  │
  │                                  │
  │════ Canal WebSocket ouvert ═════ │
  │                                  │
  │── Message {"type": "join"} ────► │
  │◄── Message {"type": "welcome"} ─ │
  │◄── Message {"type": "push"} ──── │  (push serveur)
  │── Message {"type": "ping"} ────► │  (keepalive)
  │◄── Message {"type": "pong"} ──── │
  │                                  │
  │── Close frame ─────────────────► │  (fermeture propre)
  │◄── Close frame ───────────────── │
  │════ Connexion TCP fermée ════════ │

Exemples de code

// Côté client (JavaScript navigateur)
const ws = new WebSocket('wss://api.exemple.com/ws');  // wss = WebSocket + TLS
 
ws.onopen = () => {
  console.log('Connexion ouverte');
  ws.send(JSON.stringify({ type: 'subscribe', channel: 'notifications' }));
};
 
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Message reçu:', data);
};
 
ws.onclose = (event) => {
  console.log('Connexion fermée:', event.code, event.reason);
  // Reconnexion automatique si nécessaire
  setTimeout(() => reconnect(), 3000);
};
 
ws.onerror = (error) => {
  console.error('Erreur WebSocket:', error);
};
 
// Envoyer un message
ws.send(JSON.stringify({ type: 'message', text: 'Bonjour' }));
 
// Fermer proprement
ws.close(1000, 'Session terminée');
# Côté serveur (Python / websockets)
import asyncio
import websockets
import json
 
connected_clients = set()
 
async def handler(websocket):
    connected_clients.add(websocket)
    try:
        async for message in websocket:
            data = json.loads(message)
 
            if data["type"] == "message":
                # Diffuser à tous les clients connectés
                for client in connected_clients:
                    if client != websocket:
                        await client.send(json.dumps({
                            "type": "message",
                            "text": data["text"],
                            "from": data.get("user")
                        }))
    finally:
        connected_clients.remove(websocket)
 
async def main():
    async with websockets.serve(handler, "0.0.0.0", 8765):
        await asyncio.Future()  # run forever
 
asyncio.run(main())

Protocoles au-dessus de WebSocket

WebSocket transporte des bytes bruts. Des protocoles applicatifs sont souvent ajoutés par-dessus :

ProtocoleUsageDescription
STOMPMessagingSimple Text Oriented Messaging Protocol — canaux, abonnements
MQTT over WSIoTProtocole léger pour appareils contraints
Socket.IOWeb temps réelBibliothèque avec fallback HTTP polling et reconnexion automatique
GraphQL SubscriptionsAPIs GraphQLRequêtes GraphQL en push via WebSocket
// Socket.IO — abstraction populaire au-dessus de WebSocket
const io = require('socket.io')(server);
 
io.on('connection', (socket) => {
  socket.on('join_room', (room) => {
    socket.join(room);
  });
 
  socket.on('message', (data) => {
    // Envoyer à tous dans la même room
    io.to(data.room).emit('message', data);
  });
});

Codes de fermeture WebSocket

CodeSignification
1000Fermeture normale
1001Endpoint parti (navigateur fermé, serveur restart)
1006Fermeture anormale (pas de Close frame reçu)
1008Message violant la politique du serveur
1011Erreur interne serveur

WebSocket vs alternatives temps réel

TechnologieDirectionConnexionCas d’usageSupport
WebSocketBidirectionnelPersistanteChat, jeux, collaborationExcellent
SSE (Server-Sent Events)Serveur → ClientPersistante (HTTP)Notifications push, live feedBon (HTTP natif)
HTTP Long PollingServeur → ClientRépétéesFallback legacyUniversel
HTTP Short PollingClient interrogeRépétéesSimple mais inefficaceUniversel
SSE (Server-Sent Events) — alternative légère pour du push unidirectionnel :
  GET /events
  Accept: text/event-stream

  data: {"type": "notification", "message": "Nouveau message"}

  data: {"type": "update", "count": 42}

WebSocket dans Kubernetes / microservices

# Ingress NGINX — activer WebSocket (nécessite les bons headers)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
spec:
  rules:
    - host: ws.exemple.com
      http:
        paths:
          - path: /ws
            backend:
              service:
                name: websocket-service
                port:
                  number: 8765

Les load balancers L4 (TCP) passent WebSocket nativement. Les load balancers L7 doivent explicitement gérer les headers Upgrade et Connection.


En relation avec