Le web en temps réel

Le web en temps réel

Historiquement, le web permettait de récupérer une ressource à la fois. Avec le temps, des APIs se sont développées permettant de rafraîchir une partie des pages sur des sites web. Les Single Page Application (SPA) permettent de ne charger qu’une fois le contenu et d’avoir une navigation réactive.

Mais qui dit navigation fluide ne veut pas forcément dire temps réel. Pourtant, entre les applications d’actualités, les alertes de production, les ouvertures de services ou même des besoins d'alarme temps réel pour les pompiers, le temps réel est devenu une nécessité pour de nombreux sites. Plusieurs solutions existent maintenant pour répondre à ces problématiques.

Dans cet article, nous examinerons plusieurs approches clés qui ont marqué l'évolution du web en temps réel, à savoir le long polling, le Server-Sent Events (SSE), les WebSockets, la WebTransport API et WebRTC.

Le polling (ou le faux temps réel)

Pour citer wikipedia :

L’attente active, en génie logiciel, ou polling est une technique de programmation que les processus utilisent lorsqu'ils vérifient de façon répétée si une condition est vraie, comme l'attente d'une entrée (clavier ou autre) ou encore la libération d'un verrou.

Éviter le polling en pré-programmant un refresh pour une ouverture de service ?

On pourrait se dire naïvement en Server Side Rendering (SSR) dans le cas où l'heure d’ouverture d’un service sur un site est déjà connue de mettre un setTimeout variable la première fois que l’utilisateur va sur la page et qu’il aura du temps réel au bon moment. Même si en théorie cette pratique semble fonctionner, dans le monde réel, elle se confronte à deux limitations importantes. La première d’entre elles est que le setTimeOut n’est pas aussi précis que ce que l’on pense. Comme le javascript est monothreadé, il peut vite se décaler de plusieurs millisecondes et dans le temps cela peut arriver à plusieurs minutes si la page reste ouverte des heures. La deuxième problématique est la charge qui sera encaissée d’un coup par le serveur en quelques secondes qui risque de faire tomber votre service n’ayant pas le temps de réagir à cette surcharge. Cette méthode est donc à éviter autant que possible.

const dateOuverture = new Date('2024-12-31').getTime()
const dateActuelle = new Date().getTime()
const timeOut = dateOuverture - dateActuelle
const rafraichissement = () => {
 window.location.reload();
}
setTimeOut(rafraichissement, timeOut)

polling

Le "polling" a été une méthode essentielle dans le fonctionnement des applications en temps réel. Il implique que le client, par exemple un navigateur web ou une application mobile, envoie une requête au serveur à des intervalles définis. Cette méthode présente l’avantage de garantir que les utilisateurs obtiennent les informations les plus récentes, peu importe la désynchronisation de leur setTimeout. Toutefois, elle demande des ressources, tant du côté du client que du serveur. En effet, chaque requête générée consomme de la bande passante et peut éventuellement surcharger le serveur. La fraîcheur de la donnée dépendra de la fréquence du timeout définie dans l’application. On pourra par exemple avoir des données mises à jour toutes les 10 minutes pour des sondes météos comme des données mises à jour toutes les secondes pour l’ouverture d’une vente flash limitée.

Cette méthode n'est pas sans inconvénient. Par exemple, dans un contexte où un nombre croissant d'utilisateurs se connectent simultanément, le "polling" peut engendrer des délais, des ralentissements voire des crashs surtout si votre temps d’actualisation est très court. Les serveurs doivent traiter plusieurs requêtes à la fois, ce qui affecte la performance globale de l’application. Malgré cette limitation, le "regular polling" demeure une solution simple pour gérer des requêtes en “quasi” temps réel (modulo le temps d’attente).

const DELAI_DE_POLLING = 10000
function poll() {
    fetch('http://example.com/')
        .then(response => response.json())
        .then(data => {
            console.log("Received data:", data);
            setTimeout(poll, DELAI_DE_POLLING);
        })
}
poll(); // Initialisation du polling

Long polling

Le long polling, souvent considéré comme le “faux temps réel”, est une technique qui a émergé pour permettre des communications asynchrones entre le serveur et le client comme une évolution du regular polling. Lorsqu'un client envoie une requête au serveur, le serveur ne répond pas immédiatement. Au lieu de cela, il maintient la connexion ouverte jusqu'à ce qu'il ait de nouvelles données à envoyer ou que la requête expire (à ce moment la requête se ferme automatiquement indiquant qu’il n’y a pas de nouvelles données). Une fois la réponse envoyée (ou échouée), le client établit une nouvelle connexion, et le processus se répète.

Cette méthode offre l'avantage de réduire le nombre de requêtes envoyées au serveur par rapport au regular polling. Cependant, elle présente des inconvénients, notamment une latence et une utilisation inefficace des ressources au vu des connexions qui restent ouvertes sur le serveur. Aussi, le risque d’attaque par déni de service (DDOS) est bien plus important. Les clients doivent établir de nouvelles connexions qui peuvent augmenter le temps de réponse. C’est pourquoi, alors que le long polling a été une étape importante dans l’évolution des mécanismes de communication web, il a rapidement été surpassé par des technologies plus efficaces.

function longPoll() {
    fetch('http://example.com')
        .then(response => response.json())
        .then(data => {
            console.log("Received data:", data);
            longPoll();
        })
        .catch(error => {
            // En cas de timeout (pas de données reçues), on relance le long polling pour écouter les nouveaux changements
            longPoll();
        });
}
longPoll();

Server-Sent Events (SSE) : Une connexion unidirectionnelle

Les Server-Sent Events, ou SSE, représentent une avancée significative par rapport au long polling. Contrairement à cette dernière, le SSE permet au serveur d'envoyer des mises à jour aux clients automatiquement via une seule connexion persistante HTTP. Cela se fait généralement en utilisant un format de type texte/event-stream, facilitant ainsi l'envoi de données en temps réel.

Les avantages du SSE résident dans sa simplicité et son efficacité. Étant donné qu’il établit une connexion unique, il réduit le besoin de requêtes répétées. Les développeurs peuvent facilement l'intégrer à leurs applications, principalement en ciblant des cas d'utilisation tels que les notifications en direct ou les flux de données (exemple : données sportives ou alertes météo). Cependant, un des inconvénients du SSE est sa limitation à une communication unidirectionnelle. Bien que cela suffise pour de nombreux cas d'utilisation, il peut ne pas convenir aux applications nécessitant l’envoi de données vers le serveur par le client. Aussi, bien que moins compliqué que le websocket, celui-ci reste compliqué à mettre en place.

// connexion à la source sse
const evtSource = new EventSource("https://example.com/sse");

// Écoute des messages
evtSource.onmessage = event => {
    console.log('Réception : ' + event.data);
};

WebSockets : La communication bidirectionnelle en temps réel

Avec les WebSockets, nous entrons dans une nouvelle dimension de la communication web en temps réel. Cette technologie fournit une connexion bidirectionnelle entre le client et le serveur, permettant aux deux parties d'envoyer des données à tout moment. Contrairement au long polling et au SSE, les WebSockets établissent un canal de communication durable qui minimise la latence et maximise l'efficacité.

Grâce aux WebSockets, les développeurs peuvent créer des applications interactives et dynamiques, notamment des jeux en temps réel, des services de messagerie et même des applications de collaboration. En passant par une simple négociation de protocole, cette technologie permet une communication synchrone, où le serveur peut pousser des informations vers le client dès qu'elles sont disponibles. Toutefois, la mise en œuvre des WebSockets peut être complexe, surtout en matière de gestion de la sécurité (injection xss, chiffrement, authentification en autorisation…) et de la scalabilité (nombre de connexions, répartition de charge entre serveurs…).

const socket = new WebSocket('ws://example.com');

socket.onopen = function(evenement) {
  console.log('Connexion établie');
  // envoi d'un message au serveur
  socket.send('connecté');
};

socket.onmessage = function(evenement) {
  console.log('Message du serveur:', evenement.data);
};

WebTransport API : Une nouvelle ère de communication

La WebTransport API est une technologie relativement récente qui vise à améliorer les communications en temps réel en permettant le transfert de données de manière flexible et performante. Ce protocole combine les meilleures caractéristiques des WebSockets et des autres méthodes tout en se basant sur des normes modernes, comme Quick UDP Internet Connections (QUIC est un protocole de couche transport à usage général conçu pour remplacer le protocole de contrôle de transmission TCP), qui informent sur sa capacité à gérer les connexions de manière plus fluide et avec une latence minime.

L’un des aspects les plus intéressants de la WebTransport API est qu’elle permet d’établir des connexions à la fois sécurisées et rapides, idéales pour les applications nécessitant un transfert de données en temps réel, comme le streaming de contenu multimédia. Son architecture adaptable ouvre également la porte à de nouvelles possibilités, notamment en prenant en charge les transmissions de données multiples (différents types de données par le même flux). Néanmoins, l’adoption de cette technologie nécessite encore des ajustements, surtout en ce qui concerne le support des navigateurs et l’interopérabilité.

const url = "https://example.com:4999/wt";

async function initTransport(url) {
  const transport = new WebTransport(url);

  await transport.ready;
const stream = await transport.createBidirectionalStream();
  const readable = stream.readable;
  const writable = stream.writable;
// ...
}


async function closeTransport(transport) {
  try {
    await transport.closed;
    console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
  } catch (error) {
    console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
  }
}

WebRTC : La communication de pair à pair

WebRTC, ou Web Real-Time Communication, est sans doute l’une des technologies les plus révolutionnaires à avoir vu le jour dans le domaine des communications en temps réel. Il permet aux navigateurs et applications web d'effectuer des appels audio et vidéo directement, sans nécessiter de plugins. En intégrant des protocoles tels que STUN et TURN, WebRTC offre une solution complète pour la communication peer-to-peer.

Un des principaux avantages de WebRTC est sa capacité à faire passer des données en temps réel entre des utilisateurs sans passer par un serveur, rendant possibles des applications de vidéoconférence et de partage de fichiers instantané. D'autre part, WebRTC fait un excellent travail en assurant la sécurité grâce au chiffrement des données. Cependant, son déploiement peut présenter des défis, notamment en matière de compatibilité entre les différents navigateurs et de gestion des ressources réseau. Cette complexité est d’autant plus grande que le nombre d'utilisateurs est important (Plus il y a d'utilisateurs, plus la bande passante nécessaire augmente, surtout dans les configurations de communication en groupe. Chaque flux vidéo ou audio peut nécessiter une quantité importante de bande passante, ce qui peut entraîner des problèmes de qualité et des latences. Aussi, des instabilités réseau d’un utilisateur peuvent impacter l’ensemble du service).

const pc = new RTCPeerConnection();
pc.onaddstream = function (obj) {
  var vid = document.createElement("video");
  document.appendChild(vid);
  vid.srcObject = obj.stream;
};

// Helper functions
function endCall() {
  const videos = document.getElementsByTagName("video");
  for (let i = 0; i < videos.length; i++) {
    videos[i].pause();
  }

  pc.close();
}

function error(err) {
  endCall();
}

Conclusion : Le futur du web en temps réel

Alors que nous avançons dans l'ère numérique, les technologies de communication en temps réel continueront d'évoluer et de jouer un rôle fondamental dans notre interaction avec le web. Du long polling aux WebSockets, en passant par le SSE, la WebTransport API et WebRTC, chaque technologie a apporté quelque chose d'unique à la table. Les développeurs se doivent de choisir judicieusement la technologie qui répond le mieux aux besoins de leurs utilisateurs tout en gardant à l'esprit les défis de mise en œuvre et d’adoption comme les onglets multiples ou les applications ouvertes en tâche de fond comme c’est de plus en plus souvent le cas avec les Progressives Web App (PWA).

À l'avenir, nous pouvons anticiper des innovations encore plus spectaculaires qui continueront de redéfinir la manière dont nous interagissons avec le web cependant, les standards existants étant durables, on peut tout à fait continuer à utiliser les standards définis pour durer des années selon nos besoins.