Kapitel 6
Weiterleitungen
Eine Ressource, die umgezogen ist
Die Leseliste kann jetzt Bücher anlegen, ersetzen und löschen, und jeder Pfad, den sie beantwortet, ist ein aktueller: /books und /books/{id}. Die erste Version dieser API lag woanders, unter /v0/books, und manche alten Clients rufen noch diese Pfade auf. Das SERVICE_CONTRACT.md dieses Kapitels, das du in Lektion 3 öffnest, hat einen neuen Abschnitt, „Old paths“, der sagt, was der Server ihnen schuldet.
Es gibt zwei einfache Antworten, und beide sind falsch. Der Server könnte /v0/books/2 mit einer 404 beantworten, was jeden alten Client an dem Tag kaputtmacht, an dem sich die Pfade ändern. Oder er könnte eine zweite Kopie jeder Route unter /v0 behalten, was funktioniert, bis jemand einen Fehler in einer Kopie behebt und in der anderen nicht, und die beiden Versionen anfangen, sich zu widersprechen.
Wohin und wie
Eine Weiterleitung ist eine 3xx-Antwort mit einem Header location. Die beiden Teile beantworten verschiedene Fragen:
locationsagt, wo die Ressource jetzt ist, zum Beispiellocation: /books/2.Der Status sagt, wie man dorthin kommt: ob der Umzug dauerhaft ist und ob ein Client, der ihm folgt, die
ändern darf.
Fünf Status tun das, und zwei Fragen ordnen sie:
POST may become GET method and body kept
permanent 301 Moved Permanently 308 Permanent Redirect
temporary 302 Found 307 Temporary Redirect
303 See Other: fetch the location with GET (or HEAD), whatever the method was
Lies es als Raster. Die Zeilen sagen, ob der Umzug dauerhaft ist: 301 und 308 bedeuten „verwende ab jetzt die neue Adresse“, 302 und 307 bedeuten „verwende sie dieses Mal und frag nächstes Mal wieder hier“. Die Spalten sagen, was mit der Methode passiert. Nach einer 307 oder 308 sendet der Client dieselbe Methode mit demselben Body an die neue Adresse, also bleibt ein PUT ein PUT. Nach einer 301 oder 302 darf ein Client ein POST in ein GET verwandeln und seinen Body weglassen; jede andere Methode bleibt erhalten. 303 steht für sich: Es bedeutet „hol jetzt diese andere Adresse“, und RFC 9110 sagt, dass dieses Holen ein GET oder ein HEAD ist. Der Code, der Weiterleitungen folgt und den du in Lektion 4 schreibst, sendet GET, und Lektion 5 zeigt eine Bibliothek, die ein HEAD als HEAD beibehält.
Browser merken sich eine dauerhafte Weiterleitung und gehen nächstes Mal vielleicht direkt zur neuen Adresse. Das ist eine Browserfunktion, die du hier nur wiedererkennen sollst; die Clients in diesem Kurs fragen jedes Mal.
Warum fünf und nicht zwei
Auf dem Papier würden zwei reichen: einer dauerhaft, einer vorübergehend. HTTP/1.0 hatte zwei Weiterleitungscodes, 301 und 302, und keiner erlaubte einem Client, die Methode von sich aus zu ändern. Browser haben sie trotzdem geändert: Nach einem POST, das mit 301 oder 302 beantwortet wurde, sendeten die meisten ein GET an die neue Adresse und ließen den Body weg, und genug Server verließen sich auf dieses Verhalten, dass man es nicht mehr als Fehler bezeichnen konnte.
Also hat HTTP Codes hinzugefügt, statt alte zu ändern. 303 sagt offen, was Browser getan haben: Hol das Ergebnis mit einem GET (oder einem HEAD). 307 und 308 sagen das Gegenteil: Behalte die Methode und den Body, egal was passiert. RFC 9110 (Abschnitt 15.4) erlaubt das alte Verhalten für 301 und 302 weiterhin, und nur für POST: Ein Client darf dort ein POST in ein GET ändern und behält jede andere Methode bei. Ein Server, der braucht, dass ein POST oder ein PUT unverändert ankommt, sendet 307 oder 308, wo überhaupt keine Änderung erlaubt ist.
Deshalb wird die Leseliste für /v0/books 308 verwenden: Der Umzug ist dauerhaft, und das PUT eines alten Clients muss den neuen Pfad als PUT erreichen, mit seinem Body.
Keine location, keine Weiterleitung
Der Status allein macht noch keine Weiterleitung. Eine 3xx, die ohne Header location kommt, gibt dem Client kein Ziel, also behandelt ein Client sie als endgültige Antwort und gibt sie zurück. Auch ist nicht jede 3xx eine Weiterleitung: 304 Not Modified, das Kapitel 8 baut, sagt „deine Kopie im Cache ist noch gut“, und hat kein location.
Einer Weiterleitung zu folgen, ist immer die Entscheidung des Clients. http.client, das du in Kapitel 3 verwendet hast, trifft keine solche Entscheidung: Es sendet eine Anfrage und gibt eine Antwort zurück. Fragt man es nach GET /v0/books/2?x=1 bei einem Server, der weiterleitet, gibt es 308 Permanent Redirect mit location: /books/2?x=1 zurück und hört dort auf. Lektion 4 schreibt den Code, der diesen Header liest und die nächste Anfrage sendet, und Lektion 5 vergleicht ihn mit einer Bibliothek, die Weiterleitungen für dich folgt.
/v0/books/{id} ist endgültig umgezogen, und alte Clients senden dorthin PUT. Welchen Status sollte der Server senden?
Nach einem Formular-POST will der Server, dass der Client die Ergebnisseite mit GET lädt. Welcher Status sagt das?
Buch 7 wird während einer Wartung eine Stunde lang unter /books/7-old ausgeliefert, und PUT muss weiter funktionieren. Welcher Status schickt Clients dorthin?
Der Server wird location: /books/2 senden, keine vollständige location gegen die angefragte URL auf.