Communication bidirectionnelle Server push et WebSockets

Server push

Problème : AJAX est unidirectionnel

  1. Le client envoie des données dans la requête,
  2. Le serveur répond avec des données.
  • Le serveur ne peut pas initier un transfert de données ;
  • Le serveur ne peut pas appeler des fonctions (déclencher des évènements) chez le client.

Simuler une communication bidirectionnelle (Comet)

  • Short polling, Long polling, Streaming.

Vraie communication bidirectionnelle

  • EventSource, WebSockets.

Polling

Utile pour : notifications, compatibilité avec vieux navigateurs

Short polling

  1. Le client envoie une requête AJAX à intervalles réguliers (de l’ordre de la seconde),
  2. S’il y a des notifications depuis la dernière requête, le server les envoie dans la réponse.

Long polling, Streaming

  1. Le client ouvre une connexion HTTP avec le serveur,
  2. Le serveur envoie les entêtes mais ne ferme pas la connexion,
  3. Lorsque des notifications arrivent, le serveur les envoie dans la connexion ;
  4. (long polling) Le server ferme la connexion.

Polling

Avantages

  • Compatible avec les vieux navigateurs,
  • Ne demande pas de support spécifique chez le serveur.

Désavantages

  • Gourmand en bande passante et ressources (overhead du protocole HTTP),
  • Latence.

Event stream

Format de streaming unidirectionnel Serveur → Client : la connexion reste ouverte

HTTP/1.1 200 OK
Content-Type: text/event-stream
...

data: un message

data: un autre data: message
event: toto data: un message avec un nom
data: { "msg" : ["Porquoi", "pas", "du", "JSON"] }
  1. Un message d’une ligne,
  2. Un message sur plusieurs lignes,
  3. Un message nommé,
  4. On est libres de choisir le format des données.

Plus de détails : https://hpbn.co/server-sent-events-sse/.

Exemple de event stream : serveur

app.get('/api/notifications', function(req, res) {
  res.set({                                        // Configuration des entêtes
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });                                              // On envoie les entêtes
  res.writeHead(200);
  
  var count = 0;                                   // On envoie un message
  var timer = setInterval(function() {             // toutes les 2 secondes
    res.write('data: Hello ' + count + '\n\n');
    count++;
    if (count >= 10) {                             // Après 10 messages on
	  res.end();                                   // ferme la connexion
	  clearInterval(timer);
	}
  }, 2000);
});

Exemple EventSource : client

Le client est notifié des messages du server par des évènements

var evt = new EventSource("/api/notifications");

// Messages sans nom
evt.addEventListener('message', function(e) {
  console.log(e.data);
});

// Messages nommés
evt.addEventListener('toto', function(e) {
  console.log('Évènement nommé :', e.data);
});

Web Sockets

Protocole de communication full-duplex, compatible avec HTTP.

  • Protocole applicatif au dessus de TCP : pas de overhead HTTP ;
  • Conçu pour utiliser le même port que HTTP (port 80 par défaut).
GET /app/socket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
...
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
...
  1. Le client demande une connexion web socket,
  2. Le serveur répond avec 101 Switching Protocols,
  3. Le serveur et le client établissent une connexion TCP de type Web Socket (schema ws:// ou wss://).

Exemple WebSocket : serveur

Exemple avec le paquet Node ws:

var WebSocket = require('ws');

var server = new WebSocket.Server({ port: 8080 });

server.on('connection', function connection(ws) {
  ws.on('message', function(message) {
    console.log('received:', message);
  });

  ws.send('something');
});

Exemple WebSocket : client (navigateur)

Exemple avec l’API standardisée par le W3C:

var ws = new WebSocket('ws://localhost:8080');

ws.addEventListener('open', function(e) {
  ws.addEventListener('message', function(e) {
    console.log('received:', e.data);
  });
	
  ws.send('something else');
});

Web Sockets

Avantages

  • Bidirectionnels,
  • Peu de overhead,
  • Standardisés par l’IETF en 2011 (et Candidate Recommendation du W3C),
  • Disponibles dans tous les navigateurs modernes.

Désavantages

  • Nécessitent de support dans le serveur,
  • Difficiles à configurer avec Apache+PHP.

Bibliothèques

Lectures

Fork me on GitHub