Pourquoi WebSockets avec Node.js ?
Les WebSockets sont un protocole qui permet une communication bidirectionnelle en temps réel entre le client et le serveur. Ils offrent une meilleure performance et une meilleure interaction utilisateur que les requêtes HTTP traditionnelles, ce qui est essentiel pour de nombreuses applications modernes comme les chatbots, les applications de jeu en ligne, les plateformes de collaboration en temps réel, etc.
Un cas d'usage concret serait un application de chat en direct où les utilisateurs peuvent envoyer et recevoir des messages en temps réel. Avec HTTP traditionnel, chaque message envoyé du client au serveur nécessiterait une requête entière, ce qui est inefficace et peut provoquer une perte de performance.
Prerequis
- Connaissance avancée de JavaScript
- Compréhension des bases de Node.js
- Familiarité avec les concepts d'asynchronisme en JavaScript (promises, async/await)
- Installation de Node.js et npm (Node Package Manager)
Pour tester le code, vous aurez besoin de créer un fichier app.js et d'exécuter la commande suivante dans votre terminal :
node app.js
Concepts fondamentaux
1. Serveur WebSocket avec Node.js
Un serveur WebSocket permet à des clients (navigateurs web, applications mobiles, etc.) de se connecter au serveur et d'échanger des données en temps réel.
// Importer le module 'ws'
const WebSocket = require('ws');
// Créer une instance du serveur WebSocket
const wss = new WebSocket.Server({ port: 8080 });
// Lister sur les connexions entrantes
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
// Envoyer un message de réponse au client
ws.send('Hello, you sent -> ' + message);
});
});
2. Client WebSocket en JavaScript
Un client WebSocket peut se connecter à un serveur WebSocket et échanger des messages avec lui.
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client</title>
</head>
<body>
<script>
// Créer une instance du client WebSocket
const socket = new WebSocket('ws://localhost:8080');
// Lister sur l'événement 'open'
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Lister sur l'événement 'message'
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
</script>
</body>
</html>
3. Gestion des erreurs et fermeture de connexion
Il est important de gérer les erreurs et la fermeture de connexion pour assurer une meilleure robustesse du serveur WebSocket.
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('Hello, you sent -> ' + message);
});
// Gestion de l'événement 'close'
ws.on('close', function close() {
console.log('Client disconnected');
});
// Gestion de l'événement 'error'
ws.on('error', function error(err) {
console.error('WebSocket Error:', err);
});
});
Mise en pratique : projet fil rouge
Mini-projet : Chatbot en temps réel avec WebSockets
Dans ce mini-projet, nous allons créer un chatbot simple qui permet aux utilisateurs de s'envoyer des messages en temps réel.
Étape 1: Créer le serveur WebSocket
Créez un fichier app.js et ajoutez le code suivant :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
broadcast(message, ws);
});
ws.on('close', function close() {
console.log('Client disconnected');
});
});
function broadcast(data, sender) {
wss.clients.forEach(function each(client) {
if (client !== sender && client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
}
Étape 2: Créer le client HTML
Créez un fichier index.html et ajoutez le code suivant :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Chatbot</title>
</head>
<body>
<div id="chatbox"></div>
<input type="text" id="messageInput" placeholder="Type a message...">
<button onclick="sendMessage()">Send</button>
<script>
const socket = new WebSocket('ws://localhost:8080');
const chatbox = document.getElementById('chatbox');
const input = document.getElementById('messageInput');
socket.addEventListener('open', function () {
console.log('Connected to server');
});
socket.addEventListener('message', function (event) {
chatbox.innerHTML += '<p>' + event.data + '</p>';
});
function sendMessage() {
const message = input.value;
if (message) {
socket.send(message);
input.value = '';
}
}
</script>
</body>
</html>
Étape 3: Exécuter le serveur
Assurez-vous que votre serveur est en cours d'exécution :
node app.js
Ouvrez index.html dans plusieurs navigateurs et essayez de vous envoyer des messages en temps réel. Vous devriez voir les messages s'afficher dans tous les navigateurs ouverts.
Erreurs frequentes et debugging
1. Connexion refusée : "WebSocket connection to 'ws://localhost:8080' failed"
Code incorrect :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
Code correct :
const WebSocket = require('ws');
const server = require('http').createServer();
const wss = new WebSocket.Server({ server });
server.listen(8080, function listening() {
console.log('Listening on %d', server.address().port);
});
2. "WebSocket is closed before the connection is established"
Code incorrect :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.send('Hello, world!');
});
wss.close();
Code correct :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.send('Hello, world!');
});
3. "WebSocket is closed abnormally"
Code incorrect :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('Hello, you sent -> ' + message);
});
});
setTimeout(() => wss.close(), 1000);
Code correct :
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('Hello, you sent -> ' + message);
});
});
Pour aller plus loin
1. Authentification et sécurité des messages
Pour une application de chat en direct, il est important d'ajouter une couche de sécurité pour authentifier les utilisateurs et crypter les messages.
Lien : Node-Auth0
2. Stockage des messages
Il serait pratique de stocker les messages envoyés afin qu'ils soient accessibles même quand un utilisateur n'est pas en ligne.
Lien : MongoDB
3. Échelle et performance
Pour une application à grande échelle, il est important d'évaluer les performances et de mettre en œuvre des mécanismes d'échelle si nécessaire.
Lien : Cluster Node.js
Défi pratique
Créez un simple système de chat avec fonctionnalités supplémentaires comme la possibilité d'envoyer des fichiers, des emojis, et la gestion des utilisateurs en ligne.