0%

De standaardclient en statusklassen · oefening

Headers van het antwoord lezen

De statusklasse vertelt een client wie er aan zet is. Sommige zetten hebben meer nodig. Hoe lang moet de client na een 429 wachten? Is deze body wel , of een HTML-foutpagina van een server ertussen? De antwoorden komen in de headers van het antwoord. Deze les voegt de twee headers die een beslissing het vaakst nodig heeft toe aan het record dat get_json teruggeeft: Content-Type en Retry-After.

Twee manieren om een header te lezen

Je record bevat al elke header in de die je uit getheaders() bouwde: namen in kleine letters, elk met een . Het antwoordobject heeft ook een voor één header tegelijk:

response.getheader("Retry-After")

getheader(name) vindt de naam in elke schrijfwijze, dus "retry-after", "Retry-After" en "RETRY-AFTER" vinden allemaal een regel die de server schreef als Retry-After: 1. Het geeft de waarde terug als , of None als de header ontbreekt; een tweede , zoals in getheader("Retry-After", "0"), vervangt die None. Komt de naam meer dan eens voor, dan voegt getheader de waarden samen tot één string met ", " ertussen.

Beide manieren zijn niet hoofdlettergevoelig, en elk past bij een andere taak. Voor een header met één waarde, zoals Content-Type of Retry-After, geeft getheader je die waarde direct. Voor een header die herhaald kan worden, waarbij je elke waarde apart nodig hebt, houdt de dict ze uit elkaar: X-Trace: a en X-Trace: b blijven daar ["a", "b"], terwijl getheader("X-Trace") "a, b" teruggeeft. Samenvoegen is alleen veilig als er geen komma in een waarde kan staan, en dat geldt niet voor elke header; hoofdstuk 7 komt er een tegen waarvoor het niet geldt.

Wat je niet moet doen, is de naam opzoeken in een dict die gebouwd is met de schrijfwijze van de server zelf. Een server kan retry-after of RETRY-AFTER schrijven, en zegt dat veldnamen niet hoofdlettergevoelig zijn, dus {"Retry-After": "1"}.get("Retry-After") werkt alleen met een server die de naam op jouw manier schreef.

Retry-After is tekst

Retry-After vertelt de client wanneer hij opnieuw mag vragen. Het bevat ofwel een aantal seconden, zoals Retry-After: 120, ofwel een datum, zoals Retry-After: Fri, 31 Dec 1999 23:59:59 GMT. Omdat het een datum kan zijn, is de waarde niet altijd een getal, en houdt get_json hem als de tekst die aankwam. Er een wachttijd van maken, en beslissen of er überhaupt opnieuw geprobeerd wordt, is de taak van wie get_json aanroept.

De regel uit Python in Practice voor 429 geldt hier nog steeds: het is een signaal om te stoppen. get_json meldt wat de server zei en keert terug; het wacht niet en verstuurt het verzoek niet opnieuw.

De kop van een antwoord bevat de regel Retry-After: 1. Wat geeft response.getheader("retry-after") terug?

Content-Type heeft parameters

Content-Type noemt het formaat van de body. practice-api stuurt Content-Type: application/json; charset=utf-8. Het deel vóór de ; is het mediatype, application/json; wat volgt is een , hier de tekencodering van de tekst. Een andere server stuurt misschien application/json zonder parameter, of application/json;charset=UTF-8 zonder spatie. Les 4 gebruikt het mediatype om te beslissen of een body als JSON gedecodeerd wordt. Houd voorlopig de hele waarde zoals hij aankwam.

Bekijk een 429

Het rate-limitscenario antwoordt op basis van het pogingnummer dat je meestuurt: pogingen 1 en 2 krijgen een 200, en pogingen 3 tot en met 10 krijgen een 429. Het onthoudt niets tussen verzoeken, dus poging 3 is altijd een 429. Onder de van dat antwoord staan deze, die practice-api zelf stuurt:

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

Je opdracht

  1. Voeg in wire.py twee sleutels toe aan het record dat get_json teruggeeft: "content_type", uit response.getheader("Content-Type"), en "retry_after", uit response.getheader("Retry-After"). Lees beide binnen het with-blok, houd elk als de tekst die aankwam, en laat None staan als de header ontbreekt. Houd alles wat les 1 schreef.

  2. Bekijk een live 429:

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

Het zou 429 application/json; charset=utf-8 1 moeten afdrukken. Probeer ook attempt=2: de 200 die terugkomt, heeft geen Retry-After, dus zijn retry_after is None.

Druk daarna op Check my work. Je client leest nu de status en de headers die een beslissing nodig heeft, maar behandelt nog steeds elke body op dezelfde manier. De volgende les deelt elk scenario in op klasse en houdt de foutbodies.

Opdracht

Voeg de headers die een beslissing nodig heeft toe aan het record dat get_json teruggeeft.

  • "content_type": de van response.getheader("Content-Type"), zoals hij aankwam, inclusief .

  • "retry_after": de waarde van response.getheader("Retry-After"), bewaard als tekst, niet omgezet in een getal.

  • Beide zijn None als het antwoord zo’n header niet heeft.

  • Houd alles uit les 1: één verbinding met de time-out, één GET met de oefenheader, de status, reason, headerdict en body, en de verbinding gesloten op elk pad.

  • get_json wacht niet en verstuurt het verzoek niet opnieuw na een 429; het geeft het record terug.

Voer python -c "import wire; r = wire.get_json('/v1/scenarios/rate-limit?attempt=3'); print(r['status'], r['content_type'], r['retry_after'])" uit in de om een live 429 te zien.

Druk daarna op Check my work. Die roept get_json aan met een vervanger voor make_connection waarvan de gescripte antwoorden headernamen in ongebruikelijke schrijfwijzen bevatten, zoals rEtRy-AfTeR: 3: een 429, een 503 met Retry-After, en antwoorden zonder een van beide headers. Ze controleert de twee nieuwe sleutels, dat het record en het sluiten uit les 1 nog kloppen, en dat get_json niet wacht en geen tweede verzoek verstuurt. Niets uit je terminal wordt beoordeeld.