http.createServer() crée un serveur web à partir d'une fonction, le handler de requêtes, que Node appelle à chaque requête entrante avec deux objets : req (la méthode, l'URL et les en-têtes envoyés par le client) et res (ce que vous renvoyez). Définissez un code de statut et des en-têtes sur res, puis appelez res.end() avec le corps. server.listen(3000) commence à accepter les connexions sur le port 3000.
La première requête répond You asked for GET /hello?name=Ada, et la Console affiche la même méthode et la même URL. Envoyez DELETE /anything depuis la barre de requête : le même handler y répond, car un serveur http simple n'a pas de routes. Toutes les requêtes passent par cette unique fonction.
Envoyer du JSON et définir le code de statut
res.writeHead(status, headers) définit le code de statut et les en-têtes en un seul appel. Pour du JSON, définissez Content-Type: application/json et envoyez le résultat de JSON.stringify() ; res.end() n'accepte qu'une chaîne ou un Buffer.
GET /users?limit=1 renvoie [{"id":1,"name":"Ada"}]. req.url contient le chemin plus la query string, donc new URL(req.url, 'http://localhost') le sépare en pathname et searchParams (la base n'est là que parce que URL a besoin d'une adresse absolue). Envoyez GET /nothing et le statut passe à 404.
Router les requêtes avec un switch
Une petite API n'a besoin de rien de plus qu'un switch sur la méthode et le chemin. Construisez une clé comme 'GET /users' et donnez à chaque route son propre case :
Envoyez POST /users avec le corps {"name": "Grace"} : la réponse est 201 avec {"id":2,"name":"Grace"}, et GET /users liste maintenant les deux utilisateurs. Envoyez le même POST avec le corps hello et vous obtenez 400 avec {"error":"Body must be JSON"}.
Lire un corps POST
Node ne parse pas le corps pour vous. req est un stream lisible, et le corps arrive par morceaux via les événements data, puis end se déclenche quand il est complet. readBody() ci-dessus rassemble les morceaux dans une chaîne et renvoie une promesse, pour que le handler puisse l'attendre avec await. Comme req est un itérable asynchrone, cette boucle fait le même travail :
let data = '';
for await (const chunk of req) data += chunk;
const body = JSON.parse(data);
Un vrai serveur limite aussi la taille (arrêter la lecture et répondre 413 dès que data.length dépasse une limite) et vérifie req.headers['content-type'] avant d'appeler JSON.parse.
Erreurs fréquentes
Oublier res.end(). Une branche qui définit un statut sans jamais terminer la réponse laisse le client attendre jusqu'au timeout.
Définir un en-tête après le corps. Une fois que res.end() ou le premier res.write() s'est exécuté, les en-têtes sont envoyés, et res.setHeader() lève ERR_HTTP_HEADERS_SENT. Utilisez return quand vous envoyez une réponse plus tôt, comme dans les exemples.
Comparer req.url avec un chemin. req.url contient la query string, donc req.url === '/users' est faux pour /users?limit=1. Comparez pathname.
Quand utiliser Express à la place
Le module http suffit pour un health check, un récepteur de webhooks ou pour comprendre comment fonctionne HTTP. Dès que vous avez besoin de paramètres de route comme /users/:id, du parsing de corps JSON, de middlewares et de gestion des erreurs, vous finissez par écrire votre propre petit framework. Express est ce framework, construit sur les mêmes objets req et res ; le routing Express montre la même API avec app.get() et app.post().
Questions fréquentes
Quelle différence entre res.write et res.end ?
res.write() envoie un morceau du corps et garde la réponse ouverte, vous pouvez donc l'appeler plusieurs fois. res.end() envoie un dernier morceau optionnel et termine la réponse. Chaque réponse a besoin d'exactement un res.end().
Comment arrêter un serveur HTTP Node ?
Appelez server.close(). Il cesse immédiatement d'accepter de nouvelles connexions et exécute son callback une fois que les connexions ouvertes sont terminées, ce dont un arrêt propre sur SIGTERM a besoin.
Comment utiliser HTTPS avec le module http ?
Utilisez plutôt le module https : https.createServer({ key, cert }, handler) prend le même handler plus une clé privée et un certificat. En production, un proxy comme Nginx ou la plateforme d'hébergement termine en général le TLS, et votre serveur Node reste en HTTP simple.
Sur quel port un serveur Node doit-il écouter ?
N'importe quel port libre au-dessus de 1024 fonctionne sans droits d'administrateur ; 3000 et 8080 sont courants en développement. Les hébergeurs indiquent en général le port dans une variable d'environnement, donc écrivez server.listen(process.env.PORT || 3000).