Abschlussprojekt: der Leselisten-Dienst und sein Client · Abschlussprojekt
Abschlussprojekt: Beide zusammen ausführen
Jede Hälfte wurde allein bewiesen, und die beiden haben noch nie miteinander gesprochen. Diese Lektion führt elf Befehle deines Clients gegen deinen Server aus, ausgehend von reading_server.sample_state() mit den now-
| Schritt | Befehl | now | Was passieren sollte | Exit |
|---|---|---|---|---|
| 1 | list | 0 | GET /books, zwei Bücher | 0 |
| 2 | add, Token eines Schreibers | 0 | POST /books, 201, die neue | 0 |
| 3 | show 3 | 0 | GET /books/3, frisch bis 60 | 0 |
| 4 | show 3 | 30 | nichts gesendet | 0 |
| 5 | show 3 | 60 | If-None-Match, 304, frisch bis 120 | 0 |
| 6 | update 3 über /v0, Token eines Lesers | 60 | 308, dann PUT /books/3: 403 | 2 |
| 7 | update 3 über /v0, Token eines Schreibers | 60 | 308, dann 200 mit dem neuen Titel | 0 |
| 8 | show 3 | 90 | nichts gesendet, der alte Titel | 0 |
| 9 | show 3 | 120 | If-None-Match, 200, der neue Titel | 0 |
| 10 | delete 3 über /v0 | 120 | 308, dann 204 | 0 |
| 11 | show 3 | 200 | If-None-Match, 404 | 2 |
Jede Zeile von “Not built yet” steckt darin. Die Schritte 6, 7 und 10 gehen über den alten Pfad, Schritt 5 revalidiert, Schritt 2 gibt eine Location aus, und die
Eine Weiterleitung, die du sehen kannst
In den Schritten 6, 7 und 10 folgt requests der 308 für dich, wie Kapitel 10 gezeigt hat: Es sendet dieselbe response.history ist eine response.url ist der Ort, an dem requests am Ende gelandet ist. Bei Schritt 7 enthält history eine 308, deren url die /v0-URL ist.
Der Vertrag verlangt, dass der Client das sagt: eine Zeile auf der Standardfehlerausgabe pro gefolgter Weiterleitung, followed STATUS from URL, vor jeder anderen Zeile. Die Standardausgabe bleibt für Ergebnisse, also sieht ein Skript, das die Bücherliste liest, die Zeile nie. Schreibe report_redirects(response), eine zweizeilige response.history, die status_code und url jedes Eintrags mit file=sys.stderr ausgibt. Rufe sie dann in run für jeden Befehl auf, der eine Antwort bekommen hat: direkt nach call bei list, add, update und delete und bei show, wenn cached_show eine Antwort zurückgegeben hat, an beiden Stellen vor der Fehlerprüfung.
update 3 über /v0 mit dem Token eines Schreibers gelingt. Wie viele followed-Zeilen erscheinen, und wo?
Zusehen, wie es läuft
pl_http.py startet deinen Server auf einem main, den now-Werten von oben und einer Cache-Datei in einem temporären Ordner aus. Die URLs lauten http://books.test, weil es requests ohne
python pl_http.py capstone
Für jeden Befehl gibt es die Anfragen aus, die dein Server empfangen hat, dann die
--- requests and replies ---
--- your reading_client.py show 3 --base-url http://books.test (now 30) ---
exit status: 0
standard output: ['3: Piranesi by Susanna Clarke']
standard error: []
--- requests and replies ---
request 1 GET /books/3 (If-None-Match: "6a584f0c2da517c8750cdd3157f9d6f9cc07bbd19955c92a953fcc8cb494f8a9") -> 304 Not Modified (connection 1)
Der erste Block enthält überhaupt keine Anfrage: Der in Schritt 3 gespeicherte Eintrag war frisch. Schritt 6 geht mit einem Token, das nur lesen darf, über den alten Pfad:
request 1 PUT /v0/books/3 -> 308 Permanent Redirect (connection 1)
request 2 PUT /books/3 -> 403 Forbidden (connection 1)
--- your reading_client.py update 3 --base-url http://books.test/v0 --token tok-ben-reads-K9pz --title "Piranesi (paperback)" --author "Susanna Clarke" (now 60) ---
exit status: 2
standard output: []
standard error: ['followed 308 from http://books.test/v0/books/3', '403 this token may read the list but not change it']
Zwei Anfragen haben für einen einzigen Befehl deinen Server erreicht. Die zweite bekam eine 403, keine 401, also hat requests das Token nach der Weiterleitung erneut gesendet: Es behält authorization, wenn die neue URL auf demselben Host liegt. Die Liste der Standardfehlerausgabe beginnt mit deiner followed-Zeile und endet mit der einen Fehlerzeile. Jede Anfrage sagt connection 1: requests hat über alle elf Befehle hinweg eine Verbindung offen gehalten, so wie Kapitel 9 es deinem Server zu erlauben beigebracht hat. Am Ende öffnet pl_http zwei leere Verbindungen, damit serve() seine Zahl von drei erreicht und zurückkehrt.
Frisch ist nicht dasselbe wie aktuell
Schritt 8 ist der, der falsch aussieht:
--- your reading_client.py show 3 --base-url http://books.test (now 90) ---
exit status: 0
standard output: ['3: Piranesi by Susanna Clarke']
In Schritt 7 wurde der Titel zu Piranesi (paperback), und dein Server weiß das. Dein Client hat trotzdem den alten Titel ausgegeben und nichts gesendet. Das ist richtig so. In Schritt 5 hat die 304 des Servers max-age=60 gesagt: Du darfst diese Kopie 60 Sekunden lang wiederverwenden, ohne zu fragen. Dieses Versprechen lief bis 120, und die Änderung in Schritt 7 kann keine Kopie erreichen, nach der der Client nie fragt. Schritt 9, bei 120, ist der Moment, in dem das Versprechen endet: Der Client sendet das alte Tag, das Tag passt nicht mehr, und die 200 bringt den neuen Titel. max-age tauscht Aktualität gegen eingesparte Anfragen, und der Server wählt diesen Tausch.
Schritt 8 gibt den alten Titel aus, obwohl Schritt 7 ihn geändert hat. Liegt der Client falsch?
Was bewiesen wird, und wie
Check my work liest diesen Lauf nicht. Es wiederholt jede Prüfung der Lektionen 1 und 2 und führt dann elf Befehle im Speicher aus: eine echte requests.Session, deren einziger Adapter die Bytes jeder Anfrage im selben Prozess an die Handler-Klasse deines Servers übergibt, sodass requests den 308ern folgt und die 304 so liest, wie es das in einem Netzwerk täte. Die Bücher, Titel, Tokens und die Basis-URL sind neu, MAX_AGE ist 45, und jeder Exit-Status, jede Ausgabezeile, jede followed-Zeile und jede Anzahl von Anfragen muss passen, mit TIMEOUT bei jedem Hop.
Deine Aufgabe
Schreibe
report_redirects.Rufe es in
runfür jeden Befehl auf, vor der Fehlerprüfung.Führe
python -m pytest -qundpython pl_http.py capstoneaus.Klicke auf Check my work.
Die beiden Hälften stimmen jetzt bei jedem Befehl des Vertrags überein. Die nächste Lektion schreibt die Tests, die bemerken würden, wenn eine davon damit aufhörte.
Aufgabe
Melde jede
report_redirects(response): Gib für jeden Eintrag vonresponse.history, der Reihe nach,followed STATUS from URLauf der Standardfehlerausgabe aus, mitstatus_codeundurldes Eintrags. Nichts bei einer leeren History.Rufe es in
runfür jeden Befehl auf, der eine Antwort bekommen hat (beishow, wenncached_showeine zurückgegeben hat), vor der Fehlerprüfung, damit diefollowed-Zeilen vor jeder anderen Zeile auf der Standardfehlerausgabe kommen.
Behalte jede Server- und Client-Zeile aus den Lektionen 1 und 2 bei. Führe im python -m pytest -q und python pl_http.py capstone aus.
Klicke dann auf Check my work. Es wiederholt jede Prüfung der Lektionen 1 und 2 und prüft dann report_redirects mit einer Antwort, die einer 308 und einer 301 gefolgt ist, und die erste Zeile auf der Standardfehlerausgabe von list, show, add, update, delete und einem abgelehnten update, jeweils über eine /v0-Basis-http://shelf.test:8123, MAX_AGE auf 45 gesetzt und now 0, 0, 0, 30, 60, 60, 60, 90, 120, 120, 200. Jeder Exit-Status, jede Zeile auf der Standardausgabe, jede followed-Zeile, jede Fehlerzeile, jede Anzahl von Anfragen, jedes If-None-Match und der Timeout bei jedem Hop müssen passen; danach muss main ohne Session mit make_session eine eigene erstellen. Während dein Client läuft, kann reading_client.requests nichts senden. Es liest weder dein Terminal noch den Lauf von pl_http.py.