Abschnitt 8 · Lektion 3
Die Anfrage lesen
req ist alles, was hereinkommt. Drei Dinge davon brauchst du ständig, und mit den ersten beiden
fängt jedes Routing an.
Methode und Pfad
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end(`${req.method} ${req.url}\n`);
});
server.listen(3000); req.method ist die Methode in Großbuchstaben, req.url der angefragte Pfad. Der Server oben
antwortet mit nichts anderem als diesen beiden Angaben, du kannst ihn also fragen und nachlesen, was
angekommen ist. Tipp eine andere Adresse in die Adresszeile, und der Pfad in der Antwort ändert
sich mit.
Eine andere Methode bekommst du im Browser nicht hin, der schickt beim Eintippen immer GET. Im
Terminal schon:
curl http://localhost:3000/buecher
curl -X POST http://localhost:3000/buecher
curl -X DELETE http://localhost:3000/buecher/12
Zusammen ergeben die beiden Angaben die Frage, die dein Server beantworten muss, und diese Frage hat
immer zwei Teile: GET /buecher und POST /buecher sind zwei völlig verschiedene Dinge am selben
Ort. Das eine holt die Liste, das andere legt einen Eintrag an. Wer nur auf den Pfad schaut, baut
sich einen Server, der beim Anlegen die Liste zurückgibt.
req.url ist nicht die ganze Adresse
Der Name führt in die Irre. In req.url steht nicht die Adresse, die der Nutzer eingetippt hat,
sondern nur alles ab dem Hostnamen.
import { createServer } from "node:http";
const server = createServer((req, res) => {
const adresse = new URL(req.url, "http://localhost");
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end(
[
`req.url ist: ${req.url}`,
`pathname: ${adresse.pathname}`,
`q: ${adresse.searchParams.get("q")}`,
`seite: ${adresse.searchParams.get("seite")}`,
].join("\n") + "\n"
);
});
server.listen(3000); Der Browser steht hier gleich auf /suche?q=kaffee&seite=2, und in der ersten Zeile der Antwort
siehst du, was davon in req.url ankommt. Der Hostname fehlt, das Protokoll fehlt, und der Grund
dafür ist einleuchtend: Die Anfrage ist ja schon bei dir angekommen. Wo sie hin sollte, weiß dein
Server, sonst hätte er sie nicht.
Zum Zerlegen nimmst du new URL(req.url, "http://localhost"). Das zweite Argument ist eine Basis,
die URL braucht, weil der erste Teil allein keine vollständige Adresse ist. Welchen Hostnamen du
dort hinschreibst, ist völlig egal, solange du danach nur pathname und searchParams benutzt.
Der handgestrickte Weg wäre req.url.split("?")[0], und für den Pfad allein funktioniert er sogar.
Sobald aber Werte aus der Adresszeile dazukommen, hört es auf: Kodierung, Mehrfachwerte, leere
Werte, Sonderzeichen. Das ist Lektion 8.6, und die Kurzfassung lautet, dass URL das alles schon
richtig macht.
Kopfzeilen
req.headers ist ein ganz normales Objekt mit den Kopfzeilen der Anfrage.
import { createServer } from "node:http";
const server = createServer((req, res) => {
const zeilen = Object.entries(req.headers).map(
([name, wert]) => `${name} = ${wert}`
);
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end(zeilen.join("\n") + "\n");
});
server.listen(3000); Rechts steht, was dein Browser gerade mitgeschickt hat. Schick dir selbst eine Zeile dazu, und zwar mit einem Großbuchstaben darin:
curl -H "X-Test: Hallo" http://localhost:3000/
In der Antwort steht x-test = Hallo. Die Namen sind immer kleingeschrieben, egal wie der
Aufrufer sie geschrieben hat. Das ist eine Zusage von Node und keine Zufälligkeit, auf die du dich
verlassen kannst: req.headers["x-test"] findet den Wert, req.headers["X-Test"] ist undefined.
Die Werte lässt Node dagegen so, wie sie ankamen.
Die Handvoll, die dir im Alltag wirklich begegnet:
content-typesagt, was im Inhalt der Anfrage steckt. Wichtig ab Abschnitt 10, wenn du Formulare und JSON entgegennimmst.acceptsagt, was der Aufrufer gern hätte.user-agentsagt, welches Programm anfragt.cookieträgt die Cookies, die du selbst vorher gesetzt hast. Das ist Lektion 13.3.authorizationträgt Anmeldedaten.
Und jetzt der Satz, der bleiben soll
Nichts davon darfst du glauben. Jede Kopfzeile kommt vom Aufrufer, und ein Aufrufer muss kein
Browser sein. Du hast dir gerade selbst eine ausgedacht und mitgeschickt. Genauso frei lässt sich
user-agent, accept oder authorization erfinden, probier es aus:
curl -H "User-Agent: ich bin ein Browser, ehrlich" http://localhost:3000/
Das klingt selbstverständlich, wird aber ständig vergessen. Wer die Sprache aus accept-language
liest, um eine Übersetzung zu wählen, macht alles richtig: Im schlimmsten Fall steht die Seite auf
Finnisch da. Wer aus einer Kopfzeile liest, wer der Nutzer ist, hat ein Problem, denn diese Zeile
kann sich jeder selbst schreiben.
Dieser Satz gehört hierher und nicht erst in Abschnitt 15, weil du ab der nächsten Lektion anfängst,
mit diesen Werten zu arbeiten. Merk ihn dir gleich mit: Alles aus req ist eine Behauptung, keine
Tatsache.
Zum Mitnehmen
Methode und Pfad sind die zwei Angaben, aus denen jedes Routing entsteht. Und alles, was in einer Kopfzeile steht, hat sich der Aufrufer ausgedacht.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.