Requêtes courtes (Short Polling) :
Le principe du short polling consiste à envoyer des requêtes HTTP périodiquement depuis le navigateur vers le serveur. Le serveur répond systématiquement, que des données soient disponíveis ou non. Une fois la réponse envoyée, la connexion TCP est fermée. L'implémentation reste simple : on utilise XMLHttpRequest ou fetch avec un timer pour interroger le serveur.
window.setInterval(() => {
fetch(serveurUrl).then(reponse => {
// traitement des données reçues
})
}, 5000);
Avantages : Mise en œuvre aisée.
Inconvénients : Décalage des données, nombreuses requêtes inutiles, failles de sécurité, consommation excessive de ressources.
Requêtes persistantes (Long Polling) :
Avec le long polling, la requête du client reste bloquée côté serveur jusqu'à ce que des données soient disponibles ou qu'un délai d'expiration soit atteint. Dès que le serveur répond, le client envoie immédiatement une nouvelle requête. Ce mécanisme permet d'obtenir des informations actualisées.
Code côté client :
function recupererDonnees() {
fetch(serveurUrl).then(reponse => {
recupererDonnees();
// traitement des données
}).catch(erreur => {
// expiration de la connexion
recupererDonnees();
})
}
Avantages : Meilleure optimisation que le polling classique, bonne réactivité.
Inconvénients : Connexions maintenues ouvertes consomment des ressources serveur, attente lorsque aucune donnée n'est disponible.
WebSocket :
Les méthode précédentes (short polling et long polling) utilisent toutes deux Ajax côté client pour lancer la communication, ce qui implique le protocole HTTP. Le serveur ne peut pas initier l'envoi de données vers le client.
Dans des scénarios comme les événements sportifs, les salons de discussion ou le suivi de position en temps réel, le polling s'avère inefficace car il nécessite des requêtes constantes vers le serveur. WebSocket permet au serveur d'envoyer主动ement des données au client, offrant ainsi une communication bidirectionnelle en temps réel.
Les personnnes découvrant WebSocket pourraient imagines une technologie complexe. En réalité, les API principales sont simples à maîtriser. Examinons d'abord le fonctionnement technique.
Principe de communication : Lors de l'établissement d'une connexion WebSocket, le client envoie une requête HTTP initiale contenant un en-tête Upgrade pour demander le passage au protocole WebSocket.
Établir une connexion côté client :
const connexion = new WebSocket('wss://monserveur.fr:9443');
Comme HTTP et HTTPS, WebSocket possède une version sécurisée utilisant wss. Voici les en-têtes de requête envoyés :
Accept-Encoding: gzip, deflate, br
Accept-Language: fr-FR,fr;q=0.9
Cache-Control: no-cache
Connection: Upgrade
Cookie: session=abc123; token=xyz789
Host: monserveur.fr:9443
Origin: https://monserveur.fr
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Réponse du serveur :
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Upgrade: websocket
La réponse indique le code d'état 101 Switching Protocols, confirmant le passage du protocole HTTP vers WebSocket. Une fois établie, cette connexion reste ouverte en mode bidirectionnel complet.
L'en-tête Sec-WebSocket-Key envoyé par le client est vérifié par le serveur via l'en-tête Sec-WebSocket-Accept, offrant une protection contre les connexions malveillantes ou invalides. Ce key est_generé aléatoirement par le client puis encodé en base64. Le serveur applique un algorithme fixe :
const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Chaîne fixe définie par RFC6455
const accept = base64(sha1(cleClient + GUID));
Cette chaîne GUID est стандартная et ne doit jamais être modifiée.
Le client calcule localement le même hash avec sa clé initiale. Si le result correspond, la poignée de main réussit et le code de réponse 101 confirme l'établissement de la connexion WebSocket.
Implémentons maintenant une聊天 en temps réel pour deux utilisateurs, sans médias lourds.
Client :
function initialiserConnexion() {
const socket = new WebSocket('wss://monserveur.fr:9443');
// Connexion établie
socket.onopen = () => {
console.log('Connecté au serveur WebSocket');
const payload = JSON.stringify({
expediteur: idUtilisateur,
destinataire: idAmi,
type: 'initialisation'
});
socket.send(payload);
};
// Réception des messages
socket.onmessage = (evenement) => {
const donnees = JSON.parse(evenement.data);
console.log('Nouveau message reçu :', donnees);
afficherMessage(donnees);
};
// Échec de connexion
socket.onerror = (erreur) => {
console.log('Erreur de connexion, tentative de reconnexion...');
setTimeout(initialiserConnexion, 3000);
};
// Fermeture de connexion
socket.onclose = () => {
console.log('Connexion terminée');
};
}
function afficherMessage(msg) {
const liste = document.getElementById(' listeMessages');
const element = document.createElement('li');
element.textContent = `${msg.expediteur} : ${msg.contenu}`;
liste.appendChild(element);
}
initialiserConnexion();
L'API WebSocket s'avère simple : send() pour émettre, onmessage pour recevoir. En cas d'erreur, une reconnexion automatique maintient la communication.
Serveur Node.js (bibliothèque ws) :
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const application = express();
const serveur = http.createServer(application);
const wss = new WebSocket.Server({ server: serveur });
wss.on('connection', (client) => {
// Réception d'un message du client
client.on('message', (donnees) => {
const message = JSON.parse(donnees);
const clientsConnectes = wss.clients;
if (message.type === 'connexion') {
// Enregistrer l'identifiant de session
client.identifiantSession = `${message.expediteur}-${message.destinataire}`;
} else {
// Transférer au destinataire
const sessionCible = `${message.destinataire}-${message.expediteur}`;
clientsConnectes.forEach(utilisateur => {
if (utilisateur.identifiantSession === sessionCible && utilisateur.readyState === WebSocket.OPEN) {
utilisateur.send(JSON.stringify(message));
}
})
}
})
// Déconnexion
client.on('close', () => {
console.log('Un client s\'est déconnecté');
});
});
serveur.listen(9443, () => {
console.log('Serveur WebSocket démarré sur le port 9443');
});
Le serveur dispose d'événements对称 : on('message') pour recevoir et send() pour envoyer. La communication bidirectionnelle fonctionne après établissement de la connexion.
Mécanisme de maintien de connexion (Heartebat) :
Les connexions WebSocket peuventBecome instables après périodes d'inactivité. Pour éviter les interruptions, un mécanisme de heartbeat simule des ping périodiques pour confirmer que le serveur et le client sont toujours actifs. Ces paquets techinques sont indépendants des données métier.
Après connexion établie, envoyer un heartbeat toutes les 60 secondes :
let timerHeartbeat = window.setInterval(() => {
if (connexion.readyState === WebSocket.OPEN) {
connexion.send(JSON.stringify({ type: 'heartbeat' }));
}
}, 60000);
Synthèse :
Lors de l'instanciation WebSocket, une requête HTTP est envoyée avec l'en-tête Upgrade. Le protocole bascule alors de HTTP vers WebSocket. Cette connexion persistante permet une communication bidirectionnelle complète. Les méthodes send() et l'événement onmessage échangent des données via cette connexion sécurisée.