0%

Kapitel 8

Caching und bedingte Anfragen

Darf ich diese Antwort wiederverwenden?

Kapitel 7 hat die Leseliste geschützt zurückgelassen: Eine Session sagt, wer angemeldet ist, und nur das Token eines Schreibers darf ein Buch ändern. Jeder Client lädt aber immer noch bei jeder Frage die ganze herunter. Stell dir eine Leseliste-App vor, die ihren Bildschirm aktualisiert, indem sie alle fünf Sekunden GET /books sendet. Die Bücher ändern sich ein paarmal am Tag, also wiederholt fast jede Antwort die letzte Byte für Byte. Der Server baut dasselbe noch einmal, und der Client empfängt und parst Bytes, die er schon hat.

Die Antwort von besteht aus zwei Hälften. Der Server kann sagen, wie lange eine Antwort wiederverwendet werden darf, und der Client kann fragen, ob die Kopie, die er hat, noch aktuell ist. Diese Lektion ist die erste Hälfte: ein , der sagt, was ein Client mit einer aufbewahrten Kopie tun darf. Der Rest des Kapitels baut beide Hälften in deinen Server und deinen Client ein.

Die vier Direktiven

Dieser Header ist Cache-Control. Sein ist eine durch Kommas getrennte Liste von Direktiven, etwa cache-control: max-age=60, private. Eine Direktive ist ein Name, manchmal gefolgt von = und einem Wert. Vier davon decken das meiste ab, was Server sagen:

DirektiveWas ein Client mit einer aufbewahrten Kopie tun darf
max-age=Nsie ohne Nachfrage wiederverwenden, bis sie N Sekunden alt ist; danach ist sie veraltet
no-cachesie behalten, aber vor jeder Wiederverwendung beim Server nachfragen
no-storesie überhaupt nicht behalten
privateein Cache, der einem Benutzer dient, darf sie behalten; ein gemeinsamer Cache, der vielen Benutzern dient, nicht

Ein Cache ist alles, was Antworten aufbewahrt, um sie wiederzuverwenden. Dein Client bekommt in Lektion 5 einen, und der dient einem Benutzer: dem, der ihn ausführt. Ein gemeinsamer Cache sitzt zwischen vielen Clients und einem Server, zum Beispiel ein Proxy, den eine Firma betreibt, und gibt eine gespeicherte Antwort an jeden heraus, der nach derselben fragt. Deshalb gibt es private: Eine Antwort mit den Daten einer Person darf nicht an die nächste Person weitergegeben werden. Dieser Kurs betreibt keinen gemeinsamen Cache; du musst das Wort nur wiedererkennen.

no-cache ist die Direktive, deren Name in die Irre führt. Sie bedeutet nicht „nicht cachen“. Sie bedeutet „du darfst sie behalten, aber frag mich, bevor du sie verwendest“. Nachfragen kostet wenig, wie Lektion 4 zeigt, weil der Server „immer noch dasselbe“ antworten kann, ohne den Body noch einmal zu senden. no-store ist die, die „nicht behalten“ bedeutet, und ein Server sendet sie bei Antworten, die nie in einem Cache liegen sollten, etwa einer Antwort, die nennt, wer angemeldet ist. Lektion 6 setzt sie genau auf diese Antworten.

Bei Direktivennamen spielt Groß- und Kleinschreibung keine Rolle (RFC 9111, Abschnitt 5.2), also bedeutet Max-Age=60 dasselbe wie max-age=60. Eine Antwort kann auch mehr als eine Zeile cache-control tragen, und zusammen ergeben sie eine Liste. In echten Antworten wirst du anderen Direktiven begegnen, etwa public, must-revalidate und s-maxage; dieser Kurs verwendet sie nicht.

Den Header lesen

Einen Cache-Control-Wert zu lesen, ist ein Teilen an Kommas, so wie Kapitel 1 Headerzeilen an einem Doppelpunkt geteilt hat. Sag voraus, was das Teilen allein ergibt:

Was gibt das aus?

print("max-age=60, private".split(","))

Das zweite Stück beginnt mit einem Leerzeichen, weil das Leerzeichen nach dem Komma zu keiner Direktive gehört. Deshalb werden bei jedem Stück vor dem Vergleich die Leerzeichen am Rand entfernt, und es wird kleingeschrieben, weil die Namen Groß- und Kleinschreibung ignorieren. Führ das hier aus:

Try it

Ändere value auf "no-store" oder auf "private,max-age=5" und führ es noch einmal aus. Die Stücke kommen gleich heraus, ob nach dem Komma ein Leerzeichen folgt oder nicht.

Expires und die Date-Zeile

Bevor es Cache-Control gab, sagte ein Server mit dem Header expires, wie lange eine Antwort gut bleibt. Er enthält ein Datum und eine Uhrzeit, keine Anzahl von Sekunden, im HTTP-Datumsformat: demselben Format wie die Zeile Date, die http.server auf jede Antwort setzt, die dein Server sendet. Pythons email.utils schreibt dieses Format:

import email.utils

print(email.utils.formatdate(0, usegmt=True))  # Thu, 01 Jan 1970 00:00:00 GMT

0 ist die erste Sekunde der -Zeit, der Zählung von Sekunden seit dem 1. Januar 1970 in UTC, die time.time() zurückgibt. http.server schreibt seine Zeile Date mit genau dieser , mit der aktuellen Zeit.

Ein Datum hat eine Schwäche, die eine Anzahl von Sekunden nicht hat: Es funktioniert nur, wenn die Uhr des Clients mit der des Servers übereinstimmt. Wenn eine Antwort beides trägt, gewinnt deshalb max-age. RFC 9111 (Abschnitt 5.3) sagt einem Cache, expires zu ignorieren, wann immer max-age vorhanden ist. Du wirst expires trotzdem in echten Antworten sehen, meist neben einem max-age, das für neuere Clients dasselbe sagt. Dein Server wird nur max-age senden.

Eine Antwort trägt cache-control: no-cache. Darf der Client die Antwort behalten?

Was erlaubt cache-control: private?

Eine Antwort hat expires eine Stunde in der Zukunft und cache-control: max-age=60. Wie lange ist sie frisch?

Wiederverwenden ist die halbe Geschichte. Wenn eine gespeicherte Kopie veraltet, muss der Client trotzdem den ganzen Body noch einmal herunterladen, selbst wenn sich darin nichts geändert hat. Die nächsten Lektionen lassen einen Client fragen „hat es sich geändert?“ und eine kurze Antwort bekommen, und diese Frage braucht einen Namen für eine Version eines Bodys. Lektion 2 erzeugt diesen Namen: einen Fingerabdruck, berechnet aus den Bytes des Bodys.