0%

Der Standard-Client und die Statusklassen · Übung

Antwort-Header lesen

Die Statusklasse sagt einem Client, wer am Zug ist. Manche Züge brauchen mehr als das. Wie lange sollte der Client nach einem 429 warten? Ist dieser Body überhaupt , oder eine HTML-Fehlerseite von einem Server dazwischen? Die Antworten kommen in den Antwort-Headern. Diese Lektion fügt dem Datensatz, den get_json zurückgibt, die beiden Header hinzu, die eine Entscheidung am häufigsten braucht: Content-Type und Retry-After.

Zwei Arten, einen Header zu lesen

Dein Datensatz enthält schon jeden Header in dem , das du aus getheaders() gebaut hast: kleingeschriebene Namen, jeder mit einer von . Das Antwortobjekt hat auch eine für jeweils einen Header:

response.getheader("Retry-After")

getheader(name) findet den Namen in beliebiger Schreibweise, also finden "retry-after", "Retry-After" und "RETRY-AFTER" alle eine Zeile, die der Server als Retry-After: 1 geschrieben hat. Die Methode gibt den Wert als zurück, oder None, wenn der Header fehlt; ein zweites , wie in getheader("Retry-After", "0"), ersetzt dieses None. Wenn der Name mehr als einmal vorkommt, fügt getheader die Werte zu einem String zusammen, mit ", " dazwischen.

Beide Arten ignorieren die Schreibweise, und jede passt zu einer anderen Aufgabe. Für einen Header, der einen Wert trägt, etwa Content-Type oder Retry-After, gibt dir getheader diesen Wert direkt. Für einen Header, der sich wiederholen kann und bei dem du jeden Wert einzeln brauchst, hält das Dict sie auseinander: X-Trace: a und X-Trace: b bleiben dort ["a", "b"], während getheader("X-Trace") "a, b" zurückgibt. Das Zusammenfügen ist nur sicher, wenn innerhalb eines Werts kein Komma vorkommen kann, was nicht für jeden Header gilt; Kapitel 7 begegnet einem, bei dem es nicht gilt.

Was du nicht tun solltest, ist, den Namen in einem Dict nachzuschlagen, das mit der Schreibweise des Servers gebaut wurde. Ein Server kann retry-after oder RETRY-AFTER schreiben, und sagt, dass bei Feldnamen Groß- und Kleinschreibung keine Rolle spielt, also funktioniert {"Retry-After": "1"}.get("Retry-After") nur bei einem Server, der den Namen so geschrieben hat wie du.

Retry-After ist Text

Retry-After sagt dem Client, wann er wieder fragen soll. Es enthält entweder eine Anzahl Sekunden, etwa Retry-After: 120, oder ein Datum, etwa Retry-After: Fri, 31 Dec 1999 23:59:59 GMT. Weil es ein Datum sein kann, ist der Wert nicht immer eine Zahl, und get_json behält ihn als den Text, der angekommen ist. Daraus eine Wartezeit zu machen und zu entscheiden, ob überhaupt noch einmal versucht wird, ist Sache dessen, der get_json aufruft.

Die Regel aus Python in der Praxis für 429 gilt auch hier: Es ist ein Signal zum Aufhören. get_json meldet, was der Server gesagt hat, und kehrt zurück; es schläft nicht und sendet die Anfrage nicht noch einmal.

Der Kopf einer Antwort enthält die Zeile Retry-After: 1. Was gibt response.getheader("retry-after") zurück?

Content-Type hat Parameter

Content-Type nennt das Format des Bodys. practice-api sendet Content-Type: application/json; charset=utf-8. Der Teil vor dem ; ist der Medientyp, application/json; was folgt, ist ein , hier das Zeichen-Encoding des Texts. Ein anderer Server sendet vielleicht application/json ohne Parameter, oder application/json;charset=UTF-8 ohne Leerzeichen. Lektion 4 benutzt den Medientyp, um zu entscheiden, ob ein Body als JSON dekodiert wird. Behalte vorerst den ganzen Wert so, wie er angekommen ist.

Sieh dir ein 429 an

Das Szenario für die Ratenbegrenzung antwortet nach der Versuchsnummer, die du sendest: Die Versuche 1 und 2 bekommen 200, die Versuche 3 bis 10 bekommen 429. Es merkt sich nichts zwischen Anfragen, also ist Versuch 3 immer ein 429. Unter den dieser Antwort sind diese, die practice-api selbst sendet:

Content-Type: application/json; charset=utf-8
Retry-After: 1
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 0

Deine Aufgabe

  1. Füge in wire.py dem Datensatz, den get_json zurückgibt, zwei Schlüssel hinzu: "content_type", aus response.getheader("Content-Type"), und "retry_after", aus response.getheader("Retry-After"). Lies beide innerhalb des with-Blocks, behalte jeden als den Text, der angekommen ist, und lass None, wenn der Header fehlt. Behalte alles, was Lektion 1 geschrieben hat.

  2. Sieh dir ein echtes 429 an:

python -c "import wire; r = wire.get_json('/v1/scenarios/rate-limit?attempt=3'); print(r['status'], r['content_type'], r['retry_after'])"

Es sollte 429 application/json; charset=utf-8 1 ausgeben. Probiere auch attempt=2: Das 200, das zurückkommt, trägt kein Retry-After, also ist sein retry_after gleich None.

Drücke dann Check my work. Dein Client liest jetzt den Status und die Header, die eine Entscheidung braucht, behandelt aber jeden Body noch gleich. Die nächste Lektion ordnet jedes Szenario nach Klasse und behält die Fehler-Bodys.

Aufgabe

Füge dem Datensatz, den get_json zurückgibt, die Header hinzu, die eine Entscheidung braucht.

  • "content_type": der von response.getheader("Content-Type"), so wie er angekommen ist, mit .

  • "retry_after": der Wert von response.getheader("Retry-After"), als Text behalten, nicht in eine Zahl umgewandelt.

  • Beide sind None, wenn die Antwort keinen solchen Header hat.

  • Behalte alles aus Lektion 1: eine Verbindung mit dem Timeout, ein GET mit dem Übungs-Header, Status, Statustext, Header- und Body, und die Verbindung wird auf jedem Weg geschlossen.

  • get_json wartet nach einem 429 nicht und sendet die Anfrage nicht noch einmal; es gibt den Datensatz zurück.

Führe im python -c "import wire; r = wire.get_json('/v1/scenarios/rate-limit?attempt=3'); print(r['status'], r['content_type'], r['retry_after'])" aus, um ein echtes 429 zu sehen.

Drücke dann Check my work. Die Prüfung ruft get_json mit einem Ersatz für make_connection auf, dessen geskriptete Antworten Headernamen in ungewöhnlicher Schreibweise schreiben, etwa rEtRy-AfTeR: 3: ein 429, ein 503 mit Retry-After und Antworten ohne einen der beiden Header. Sie prüft die beiden neuen Schlüssel, dass der Datensatz aus Lektion 1 und das Schließen weiterhin stimmen und dass get_json weder schläft noch eine zweite Anfrage sendet. Nichts aus deinem Terminal wird bewertet.