0%

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-, die ein Test übergeben würde, und jeder Schritt muss zum Vertrag passen:

SchrittBefehlnowWas passieren sollteExit
1list0GET /books, zwei Bücher0
2add, Token eines Schreibers0POST /books, 201, die neue wird ausgegeben0
3show 30GET /books/3, frisch bis 600
4show 330nichts gesendet0
5show 360If-None-Match, 304, frisch bis 1200
6update 3 über /v0, Token eines Lesers60308, dann PUT /books/3: 4032
7update 3 über /v0, Token eines Schreibers60308, dann 200 mit dem neuen Titel0
8show 390nichts gesendet, der alte Titel0
9show 3120If-None-Match, 200, der neue Titel0
10delete 3 über /v0120308, dann 2040
11show 3200If-None-Match, 4042

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 des Servers entscheiden jeden Exit-Code.

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 und denselben Body an die neue URL und gibt die letzte Antwort zurück. Eine hinterlässt aber eine Spur. response.history ist eine der Antworten, die vor der letzten kamen, eine pro Hop, die älteste zuerst, und 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 über 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 , den das System wählt, und führt die elf Befehle mit deinem 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 auf deinen Server lenkt.

python pl_http.py capstone

Für jeden Befehl gibt es die Anfragen aus, die dein Server empfangen hat, dann die , den Exit-Status und das, was dein Client auf jedem Strom ausgegeben hat. Die Schritte 4 und 5 sehen so aus:

--- 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

  1. Schreibe report_redirects.

  2. Rufe es in run für jeden Befehl auf, vor der Fehlerprüfung.

  3. Führe python -m pytest -q und python pl_http.py capstone aus.

  4. 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 , der dein Client gefolgt ist, und führe beide Hälften zusammen aus.

  1. report_redirects(response): Gib für jeden Eintrag von response.history, der Reihe nach, followed STATUS from URL auf der Standardfehlerausgabe aus, mit status_code und url des Eintrags. Nichts bei einer leeren History.

  2. Rufe es in run für jeden Befehl auf, der eine Antwort bekommen hat (bei show, wenn cached_show eine zurückgegeben hat), vor der Fehlerprüfung, damit die followed-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-. Zuletzt führt es elf Befehle deines Clients im Speicher gegen deinen Server aus, über eine echte requests-Session, deren einziger Adapter die Bytes jeder Anfrage an die Handler-Klasse deines Servers übergibt: Bücher, Titel und Tokens, die du noch nicht gesehen hast, die Basis-URL 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.