Caching en voorwaardelijke verzoeken · oefening
Tag elke representatie
make_etag kan elke body een naam geven, en nog geen enkel antwoord gebruikt hem. Voer het scenario etag van het hulpprogramma uit om te zien wat een client vandaag ontvangt:
python pl_http.py etag
Het stuurt GET /books/1, dan een PUT /books/1 met het voorbeeldtoken van de schrijver en een nieuwe titel, dan opnieuw GET /books/1, en aan het eind toont het de header etag van het eerste en het laatste antwoord:
--- the two etag lines ---
before the PUT: None
after the PUT: None
Geen van beide antwoorden draagt een tag, en geen van beide zegt hoe lang het mag worden hergebruikt. Deze les voegt beide toe aan elk antwoord dat ze hoort te hebben: een etag en cache-control: max-age=60.
Welke antwoorden een tag krijgen
Een tag geeft een naam aan een body die een client mag bewaren en waar hij later naar mag vragen. Dat is een geslaagde leesactie: een 200 op een GET of een HEAD op /books of op /books/{id}. Niets anders krijgt er een. Een foutbody zoals {"error": "no book has that id"} is niet iets wat een client bewaart. Het antwoord op een schrijfactie meldt wat er net gebeurde, en de volgende leesactie is degene die het bewaren waard is. /login en /me blijven zoals ze zijn. SERVICE_CONTRACT.md heeft een nieuwe sectie, “Caching”, die hetzelfde in een tabel zegt.
Elke /books, /books?limit=1 en /books/2 zijn drie verschillende representaties met drie verschillende tags, ook al delen ze boeken. Een client die naar /books?limit=1 vraagt, stuurt de tag die hij van die URL kreeg.
add_validators(response) voegt beide headers toe aan een antwoord-
response["headers"]["etag"]opmake_etag(response["body"])zetten;response["headers"]["cache-control"]opmax-age=60zetten, gebouwd uit de constanteMAX_AGEbovenaanreading_server.py, bijvoorbeeld met def"max-age={MAX_AGE}".
handle roept haar op precies twee plekken aan, de twee takken die een 200 voor een leesactie bouwen. De lijsttak wordt response = add_validators(json_response(200, {"books": books})), en de tak voor één boek doet hetzelfde met json_response(200, state["books"][book_id]).
HEAD krijgt de tag van GET
Hoofdstuk 4 leerde je server HEAD te beantwoorden met precies de headers die GET zou sturen en geen body, en de laatste regels van handle doen dat door de body leeg te maken als de HEAD is. De volgorde van die twee stappen doet er nu toe. Als de tag werd berekend nadat de body was leeggemaakt, zou een HEAD-antwoord de tag van een lege body dragen, "e3b0c442...b855", een naam voor bytes die GET nooit stuurt. Een client die een resource met HEAD controleert en de tag vergelijkt met de tag die hij heeft, zou altijd een verschil zien.
add_validators aanroepen binnen de leestakken zet de functie vóór de HEAD-regel, omdat die regel als laatste draait, na elke tak. GET en HEAD delen die takken, dus beide krijgen de tag van de volledige body, en pas daarna verliest HEAD de body.
Welke etag draagt HEAD /books?
Een schrijfactie verandert de tag vanzelf
Kijk waaruit de tag wordt berekend: de body, op het moment dat een leesactie die bouwt. Niets slaat de tag op, dus niets hoeft eraan te denken hem te veranderen. Een PUT die boek 2 hernoemt, verandert de bytes van GET /books/2, dus de volgende leesactie ervan krijgt een nieuwe tag. Dezelfde PUT verandert de /books krijgt ook een nieuwe tag, net als elke ?limit=-pagina waar boek 2 in staat. De bytes van boek 1 veranderden niet, en de tag ervan ook niet.
Een tag die op een andere manier is gebouwd, moet met de hand gelijk worden gehouden, en vroeg of laat gebeurt dat niet. Een tag die uit de id van het boek is gemaakt, blijft na een PUT hetzelfde, en een client zou de oude titel blijven tonen terwijl de server “ongewijzigd” zegt.
Welke tags veranderen na PUT /books/2?
Elke body bij elke leesactie hashen kost wat werk. Een drukke echte service berekent een tag vaak één keer, als de data verandert, en slaat hem naast de data op, wat sneller is en één ding meer om gelijk te houden. Een tag die bij elke leesactie wordt berekend, is nooit verouderd, en deze server houdt dat zo.
Jouw opdracht
Schrijf in reading_server.py add_validators(response), en roep die aan in de twee leestakken van handle, zoals hierboven. Fouten, schrijfacties en elke andere route blijven onaangeroerd. Voer daarna het scenario opnieuw uit:
python pl_http.py etag
Onder elke 200 voor een leesactie drukt het hulpprogramma nu de twee headers af, en de tags van de twee leesacties verschillen, omdat de PUT daartussen de bytes van boek 1 veranderde:
--- the two etag lines ---
before the PUT: '"ecfe550f34c7f26be888feb41dbb0bdc5dfff7e77c57a8e049eb0c721b08049b"'
after the PUT: '"929daebfa038d3a896d78c3e8b93fdac7fece4faed0d92572e8a88a4733bb5f4"'
Het antwoord op de PUT zelf draagt geen van beide headers. Klik daarna op Check my work.
Elke leesactie heeft nu een tag, en clients downloaden nog steeds elke body volledig, omdat geen van hen een tag terugstuurt. De volgende les leert je server een client te beantwoorden die dat wel doet: een verzoek dat zegt “ik heb deze tag” krijgt een 304 zonder body als de tag nog actueel is.
Opdracht
Schrijf add_validators(response) in reading_server.py en roep die aan in handle.
add_validatorszetresponse["headers"]["etag"]opmake_etag(response["body"])enresponse["headers"]["cache-control"]opmax-age=60(uitMAX_AGE), en geeft daarnaresponseterug.Roep haar in
handleaan op de 200 in de tak die boeken opsomt en op de 200 in de tak die één boek teruggeeft:response = add_validators(json_response(200, ...)). Die takken draaien vóór deHEAD-regel aan het eind vanhandle, dus eenHEAD-antwoord draagt de tag van de body dieGETstuurt.Geen enkel ander antwoord krijgt een van beide headers: fouten,
, de antwoorden op POST,PUTenDELETE,/login,/logouten/meblijven zoals ze zijn.
Voer python pl_http.py etag uit in de PUT te zien.
Klik daarna op Check my work. Die roept add_validators rechtstreeks aan, en daarna handle met een state met boeken, id’s en tokens die je nog niet hebt gezien. Hij controleert dat GET op /books, /books?limit=1 en /books/{id} een etag draagt die gelijk is aan de SHA-256-digest tussen aanhalingstekens van de body die werd verstuurd, en een cache-control die max-age=60 bevat; dat HEAD dezelfde tag, dezelfde cache-control en content-length draagt, en geen body; dat na een PUT de tags van dat boek en van /books veranderen, terwijl de tag van een ander boek dat niet doet; dat een POST en een DELETE de tag van /books veranderen; en dat 404, 405, 400, 308, 401, 403, 201, 204, het antwoord op de PUT en /me geen etag dragen. Niets uit je terminal wordt beoordeeld.