Menu

Node.js HTTP-Server: http.createServer mit Beispielen

http.createServer() nimmt eine Funktion, die bei jeder Anfrage mit req und res läuft. Aus req liest du Methode und URL, dann setzt du auf res Status, Header und Body und rufst res.end() auf.

Diese Seite enthält ausführbare Editoren. Bearbeiten, ausführen und Ausgabe sofort sehen.

http.createServer() baut einen Webserver aus einer Funktion, dem Request-Handler, den Node bei jeder eingehenden Anfrage mit zwei Objekten aufruft: req (Methode, URL und Header, die der Client geschickt hat) und res (was du zurückschickst). Setz auf res einen Statuscode und Header und ruf dann res.end() mit dem Body auf. server.listen(3000) nimmt ab dann Verbindungen auf Port 3000 an.

Die erste Anfrage antwortet mit You asked for GET /hello?name=Ada, und die Console loggt dieselbe Methode und URL. Sende DELETE /anything aus der Request-Leiste: Derselbe Handler beantwortet es, weil ein reiner http-Server keine Routen hat. Jede Anfrage geht durch die eine Funktion.

JSON senden und den Statuscode setzen

res.writeHead(status, headers) setzt Statuscode und Header in einem Aufruf. Für JSON setzt du Content-Type: application/json und sendest das Ergebnis von JSON.stringify(); res.end() nimmt nur einen String oder einen Buffer an.

GET /users?limit=1 liefert [{"id":1,"name":"Ada"}]. req.url ist der Pfad plus Query-String, deshalb zerlegt new URL(req.url, 'http://localhost') ihn in pathname und searchParams (die Basis steht nur da, weil URL eine absolute Adresse braucht). Sende GET /nothing, und der Status wird zu 404.

Anfragen mit switch routen

Eine kleine API braucht nicht mehr als ein switch über Methode und Pfad. Bau einen Schlüssel wie 'GET /users' und gib jeder Route ihr eigenes case:

Sende POST /users mit dem Body {"name": "Grace"}: Die Antwort ist 201 mit {"id":2,"name":"Grace"}, und GET /users listet jetzt beide Nutzer. Sende denselben POST mit dem Body hello, und du bekommst 400 mit {"error":"Body must be JSON"}.

Einen POST-Body lesen

Node parst den Body nicht für dich. req ist ein lesbarer Stream, und der Body kommt in Stücken über data-Events an, danach feuert end, wenn er vollständig ist. readBody() oben sammelt die Stücke in einem String und gibt ein Promise zurück, damit der Handler mit await darauf warten kann. Weil req async iterierbar ist, erledigt diese Schleife dieselbe Arbeit:

let data = '';
for await (const chunk of req) data += chunk;
const body = JSON.parse(data);

Ein echter Server begrenzt außerdem die Größe (hör auf zu lesen und antworte mit 413, sobald data.length ein Limit überschreitet) und prüft req.headers['content-type'], bevor er JSON.parse aufruft.

Häufige Fehler

res.end() vergessen. Ein Zweig, der einen Status setzt, die Antwort aber nie beendet, lässt den Client bis zum Timeout warten.

Einen Header nach dem Body setzen. Sobald res.end() oder das erste res.write() gelaufen ist, sind die Header gesendet, und res.setHeader() wirft ERR_HTTP_HEADERS_SENT. Nimm return, wenn du früh eine Antwort sendest, wie in den Beispielen.

req.url mit einem Pfad vergleichen. req.url enthält den Query-String, req.url === '/users' ist also für /users?limit=1 false. Vergleich pathname.

Wann du besser Express nimmst

Das Modul http reicht für einen Health Check, einen Webhook-Empfänger oder um zu lernen, wie HTTP funktioniert. Sobald du Routenparameter wie /users/:id, JSON-Body-Parsing, Middleware und Fehlerbehandlung brauchst, schreibst du am Ende dein eigenes kleines Framework. Express ist dieses Framework, gebaut auf denselben Objekten req und res; Express Routing zeigt dieselbe API mit app.get() und app.post().

Häufig gestellte Fragen

Was ist der Unterschied zwischen res.write und res.end?

res.write() sendet ein Stück des Bodys und hält die Antwort offen, du kannst es also oft aufrufen. res.end() sendet ein optionales letztes Stück und beendet die Antwort. Jede Antwort braucht genau ein res.end().

Wie stoppe ich einen Node HTTP-Server?

Ruf server.close() auf. Es nimmt sofort keine neuen Verbindungen mehr an und führt seinen Callback aus, wenn die offenen fertig sind, genau das, was ein sauberes Herunterfahren bei SIGTERM braucht.

Wie nutze ich HTTPS mit dem http-Modul?

Nimm stattdessen das Modul https: https.createServer({ key, cert }, handler) nimmt denselben Handler plus einen privaten Schlüssel und ein Zertifikat. In Produktion beendet meist ein Proxy wie Nginx oder eine Hosting-Plattform TLS, und dein Node-Server lauscht weiter auf einfachem HTTP.

Auf welchem Port sollte ein Node-Server lauschen?

Jeder freie Port über 1024 funktioniert ohne Admin-Rechte; 3000 und 8080 sind in der Entwicklung üblich. Hosting-Plattformen geben den Port meist in einer Umgebungsvariable vor, schreib also server.listen(process.env.PORT || 3000).

Illustration der Programmiersprachen bei Coddy

Lerne mit Coddy zu programmieren

Los geht's