Abschnitt 8 · Lektion 5
Routing von Hand
Routing heißt: aus der Anfrage ableiten, welche Antwort dran ist. Du hast dafür alles beisammen, denn mehr als Methode und Pfad braucht es nicht.
Diese Lektion ist die, auf die Abschnitt 9 antwortet. Wer sie geschrieben hat, hält app.get()
später für eine Abkürzung. Wer sie überspringt, hält es für Magie.
Eine Kette von Bedingungen
import { createServer } from "node:http";
const server = createServer((req, res) => {
const pfad = new URL(req.url, "http://localhost").pathname;
if (req.method === "GET" && pfad === "/buecher") {
res.end("Liste der Buecher");
return;
}
if (req.method === "POST" && pfad === "/buecher") {
res.statusCode = 201;
res.end("Buch angelegt");
return;
}
res.statusCode = 404;
res.end("nicht gefunden");
});
server.listen(3000); Das ist schon das ganze Verfahren. Für jede Route eine Bedingung, darin die Antwort, danach ein
return, damit es nicht weitergeht.
Geprüft wird immer beides, Methode und Pfad. GET /buecher holt die Liste, POST /buecher legt
einen Eintrag an. Derselbe Ort, zwei völlig verschiedene Aufgaben. Wer nur den Pfad abfragt, baut
sich einen Server, der beim Anlegen die Liste ausgibt und sich wundert. Rechts steht die Liste, denn
der Browser fragt mit GET. Die andere Hälfte derselben Adresse holst du im Terminal:
curl -i -X POST http://localhost:3000/buecher
curl -i http://localhost:3000/zeitschriften
Und es fällt schon bei zwei Routen auf, wie viel Wiederholung darin steckt: dieselbe Bedingung mit
zwei Vergleichen, dieselben drei Zeilen zum Antworten, dasselbe return. Bei fünf Routen ist die
Funktion unübersichtlich, bei fünfzehn sucht man ernsthaft. Merk dir das Gefühl, es ist der Grund
für den nächsten Abschnitt.
Der Standardfall ist Pflicht
Ganz unten steht, was passiert, wenn keine Bedingung getroffen hat. Diese Zeilen sehen aus wie Beiwerk, sind aber der wichtigste Teil.
import { createServer } from "node:http";
const server = createServer((req, res) => {
if (req.url === "/buecher") {
res.end("Liste der Buecher");
return;
}
// Und sonst? Nichts. Kein res.end, kein Standardfall.
});
server.listen(3000); Ohne sie passiert nämlich das hier: Die Funktion läuft durch, findet nichts, ist fertig, und
niemand hat geantwortet. Kein Fehler, kein 404, keine Meldung. Der Aufrufer wartet, bis er
aufgibt. Rechts steht /buecher und alles sieht gut aus. Tipp /zeitschriften in die Adresszeile,
und die Seite lädt, bis du sie stoppst. Im Terminal mit Frist:
curl --max-time 3 http://localhost:3000/zeitschriften
Das ist derselbe Fehler wie das vergessene res.end() aus Lektion 8.1, nur mit anderem Gesicht.
Dort war die eine Antwort nicht abgeschlossen, hier gibt es überhaupt keine. Für den Aufrufer sieht
beides gleich aus, und deshalb erkennst du beides am selben Symptom: Eine Anfrage, die hängt statt
einen Fehler zu bekommen, hat einen Zweig gefunden, der nicht antwortet.
Ein Server, der auf Unbekanntes mit 404 antwortet, ist nicht nur höflicher. Er ist auch der einzige, den man sinnvoll benutzen kann.
Platzhalter, und warum sie unangenehm werden
Bisher waren alle Pfade fest. Sobald aber /buecher/12 und /buecher/13 dieselbe Route sein
sollen, geht das nicht mehr mit einem Vergleich.
import { createServer } from "node:http";
const server = createServer((req, res) => {
const pfad = new URL(req.url, "http://localhost").pathname;
const teile = pfad.split("/").filter((teil) => teil !== "");
res.setHeader("Content-Type", "text/plain; charset=utf-8");
if (teile[0] === "buecher" && teile.length === 2) {
res.end(`${pfad} zerfaellt in ${JSON.stringify(teile)}\nBuch ${teile[1]}\n`);
return;
}
res.statusCode = 404;
res.end(`${pfad} zerfaellt in ${JSON.stringify(teile)}\nnicht gefunden\n`);
});
server.listen(3000); split("/") und das filter gegen die leeren Stücke, die am Anfang und am Ende entstehen. Danach
die Länge prüfen, damit /buecher/12/seiten nicht mit durchrutscht, und den Wert an der richtigen
Stelle herausgreifen. Das Beispiel schreibt die Zerlegung in die Antwort, du kannst ihr also beim
Arbeiten zusehen: Tipp /buecher, /buecher/13 und /buecher/12/seiten in die Adresszeile und
vergleiche, was in der ersten Zeile steht.
Für eine Route ist das in Ordnung. Für zehn Routen, von denen manche einen und manche zwei Platzhalter haben, schreibst du eine kleine Mustererkennung, und irgendwann merkst du, dass du eine Bibliothek gebaut hast. Genau an diesem Punkt hört Abschnitt 8 auf und Abschnitt 9 fängt an.
Und einen Wert hat dieser Umweg trotzdem: Wenn du gleich /buecher/:id schreibst, weißt du, welche
zehn Zeilen dahinter verschwinden. Das ist der Unterschied zwischen einem Werkzeug benutzen und
einem Werkzeug vertrauen.
Zum Mitnehmen
Methode und Pfad zusammen ergeben eine Route. Und der Standardfall ganz unten ist Pflicht, sonst hängt die Anfrage einfach.
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.