Créer un serveur HTTP
Le module http natif
Node.js inclut un module http intégré — pas besoin de l'installer. Il permet de créer
un serveur web capable d'écouter des connexions entrantes et de répondre à chaque requête.
La fonction centrale est http.createServer(callback). Elle reçoit
une fonction de rappel exécutée à chaque requête, avec deux objets : req (la requête)
et res (la réponse).
const http = require('http');
const server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Bonjour depuis Node.js !');
});
server.listen(3000, function() {
console.log('Serveur démarré sur http://localhost:3000');
});
Lance ce fichier avec node server.js puis ouvre http://localhost:3000
dans ton navigateur. Tu verras le texte s'afficher immédiatement.
L'objet req — la requête entrante
L'objet req (de type IncomingMessage) expose toutes les informations
envoyées par le client :
req.method— méthode HTTP :"GET","POST","PUT","DELETE"…req.url— chemin demandé, ex."/articles"ou"/api/users?page=2"req.headers— objet contenant tous les headers HTTP envoyés par le clientreq.headers['content-type']— type du contenu envoyé (pour les POST)req.headers['authorization']— token d'authentification si présent
http.createServer(function(req, res) {
console.log('Méthode :', req.method);
console.log('URL :', req.url);
console.log('Headers :', req.headers);
res.end('Requête reçue');
}).listen(3000);
L'objet res — construire la réponse
L'objet res (de type ServerResponse) te permet de construire et d'envoyer
la réponse HTTP. Trois méthodes clés :
res.writeHead(statusCode, headers)— définit le code de statut et les headers de réponse. Doit être appelé avantwriteouend.res.write(data)— envoie un fragment du corps de la réponse (peut être appelé plusieurs fois).res.end(data)— termine la réponse, avec un dernier fragment optionnel. Obligatoire pour clore la connexion.
// Répondre avec du JSON
function jsonResponse(res, statusCode, data) {
res.writeHead(statusCode, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
res.end(JSON.stringify(data));
}
// Codes de statut courants
// 200 OK, 201 Created, 400 Bad Request
// 404 Not Found, 500 Internal Server Error
N'oublie jamais res.end(). Si tu ne termines pas la réponse,
le navigateur reste en attente indéfiniment. En cas de plantage du callback, pense à entourer
ton code d'un try/catch qui appelle res.end() dans le bloc catch.
Routing manuel — switch sur l'URL et la méthode
Sans framework, le routing consiste à inspecter req.url et req.method
pour décider quelle logique exécuter. Un switch (ou des if/else) suffit
pour un petit serveur.
http.createServer(function(req, res) {
const { method, url } = req;
if (method === 'GET' && url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Accueil</h1>');
} else if (method === 'GET' && url === '/api/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: 'Alice' }]));
} else if (method === 'POST' && url === '/api/users') {
// Traiter la création (voir section suivante)
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Utilisateur créé' }));
} else {
res.writeHead(404);
res.end('Page non trouvée');
}
}).listen(3000);
Lire le body d'une requête POST
Contrairement aux frameworks, le module http natif ne lit pas automatiquement le corps
de la requête. Les données arrivent par morceaux (chunks) via l'événement data,
et tu dois les assembler dans l'événement end.
http.createServer(function(req, res) {
if (req.method === 'POST' && req.url === '/data') {
let body = '';
// Chaque fragment de données déclenche 'data'
req.on('data', function(chunk) {
body += chunk.toString();
});
// Quand tout est reçu, 'end' est émis
req.on('end', function() {
try {
const data = JSON.parse(body);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ recu: data }));
} catch (e) {
res.writeHead(400);
res.end('JSON invalide');
}
});
}
}).listen(3000);
Servir un fichier HTML statique
Pour renvoyer un fichier HTML depuis le disque, on combine le module http avec
le module fs vu à la leçon précédente.
const http = require('http');
const fs = require('fs');
const path = require('path');
http.createServer(function(req, res) {
if (req.method === 'GET' && req.url === '/') {
const filePath = path.join(__dirname, 'public', 'index.html');
fs.readFile(filePath, function(err, data) {
if (err) {
res.writeHead(404);
res.end('Fichier introuvable');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(data);
});
}
}).listen(3000);
Gérer les erreurs 404
Toute requête qui ne correspond à aucune route connue doit recevoir une réponse 404. Sans cette gestion explicite, le navigateur reste suspendu indéfiniment (pas de réponse = timeout).
http.createServer(function(req, res) {
// ... tes routes connues ici ...
// Fallback 404 — toujours en dernier
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: 'Route introuvable',
method: req.method,
url: req.url
}));
}).listen(3000);
Une seule réponse par requête. Si tu appelles res.writeHead()
ou res.end() deux fois pour la même requête, Node.js lève une erreur
"Cannot set headers after they are sent". Assure-toi que chaque branche de
ton routing appelle res.end() exactement une fois, et utilise return
pour stopper l'exécution après l'envoi.
Pourquoi on utilise Express ensuite
Créer un serveur HTTP natif est très instructif, mais rapidement fastidieux. Regarde ce que tu dois gérer manuellement :
- Parser le body JSON à la main (events
data+end) - Inspecter
req.urletreq.methoddans chaque route - Écrire les headers
Content-Typesur chaque réponse - Gérer le 404 en fallback
- Extraire les paramètres d'URL (
/users/42→id = 42) - Lire les query strings (
?page=2&limit=10)
Express fait tout ça pour toi en ajoutant un système de routing déclaratif,
un middleware de parsing JSON (express.json()), et des méthodes utilitaires
comme res.json(), res.status() ou req.params.
Ce que tu écris en 60 lignes avec http natif s'écrit en 15 lignes avec Express —
sans rien perdre en flexibilité.
http.createServer(callback)crée un serveur. Le callback reçoitreqetresà chaque requête.req.method+req.urlpermettent de router manuellement les requêtes.res.writeHead(status, headers)définit le statut et les headers ;res.end(body)termine la réponse.- Le body POST arrive en chunks via
req.on('data')et se finalise dansreq.on('end'). - Toujours prévoir un fallback 404 — sans réponse, le navigateur attend jusqu'au timeout.
- Express remplace tout ce boilerplate par un routing déclaratif et des middlewares réutilisables.