Zelf HTTP serveren · oefening
HEAD beantwoorden zoals GET
In hoofdstuk 1 gaf je read_body na een HEAD-verzoek b"" terug zonder iets te lezen, omdat een antwoord op HEAD geen body heeft, ook als de kop een lengte aankondigt. Dat was de client die de server vertrouwde. Nu ben jij de server, en je handle beantwoordt HEAD met 405, omdat les 4 alleen GET toestond. Voer het scenario voor deze les uit, een GET /books en daarna een HEAD /books:
python pl_http.py head
De GET krijgt de HEAD krijgt 405 Method Not Allowed met allow: GET, en onder dat antwoord drukt pl_http nog één regel af, die de bytes telt die followed the reply en ze laat zien: je foutbody. pl_http leest, zoals elke client, geen body na HEAD, dus die bytes zijn extra; ze kwamen aan omdat niets tussen je handle en de http.server verstuurt het, ook na HEAD. Geen body sturen na HEAD is jouw taak.
Eén regel aan het eind van handle
HEAD vraagt om precies wat GET zou krijgen, zonder de body: dezelfde status en dezelfde headers. Een client gebruikt het om te zien of iets bestaat, of hoe groot het is, zonder het te downloaden. HEAD /books is dus een 200 met de headers van de lijst, en HEAD /nowhere is een 404 met de headers van het foutantwoord.
De eenvoudigste manier om dat allemaal goed te krijgen, is één regel aan het eind van handle, na het routeren. Routeer HEAD precies zoals GET, bewaar het antwoord in een
if method == "HEAD":
response["body"] = b""
return response
Elke tak daarboven, de lijst, de 404 en de 405, beantwoordt HEAD dan zoals hij GET beantwoordt, zonder de body. Een regel die alleen binnen de tak voor /books staat, zou na HEAD /nowhere nog steeds de body van de 404 versturen.
Waarom zet je de HEAD-regel na het routeren in plaats van binnen de tak voor /books?
De lengte beschrijft nog steeds GET
De regel maakt de body leeg en laat de headers met content-length blijft wat het was: de lengte van de body die GET zou versturen. De definitie van HEAD in GET zou hebben gestuurd, en staat hem toe velden weg te laten waarvan hij de content-length op een antwoord op HEAD dus sturen of weglaten, maar als hij er een stuurt, moet de waarde de lengte zijn die GET zou versturen (sectie 8.6). De regel van deze server, vastgelegd in SERVICE_CONTRACT.md, is hem te sturen, omdat een client zo de grootte leert zonder de download. Een lengte van 0 zou beweren dat de lijst leeg is.
De clientkant is al veilig. http.client leest geen body na HEAD, wat de lengte ook zegt, en je wire.py deed dat ook niet. Een body die toch wordt verstuurd, blijft ongelezen in de verbinding. Onder HTTP/1.0 sluit de server na één antwoord en verdwijnen de verdwaalde bytes met de verbinding. Vanaf hoofdstuk 9 vervoert één verbinding meerdere verzoeken, en die bytes zouden worden gelezen als het begin van het volgende antwoord.
GET /books verstuurt 132 bodybytes. Welke content-length heeft HEAD /books op deze server?
Je opdracht
Zet bovenaan
handlemethod = request["method"]. RouteerHEADdaarna zoals jeGETrouteert: op/booksantwoordtmethod == "GET" or method == "HEAD"met de lijst.Bewaar het antwoord van elke tak in één variabele,
response, en geef die één keer terug, aan het eind.Zet vlak voor die
returnresponse["body"] = b""als deHEADis.Verander de 405 in
not_allowed("GET, HEAD"), omdat/booksnu beide ondersteunt.
Voer python pl_http.py head opnieuw uit en vergelijk de twee regels server -> client. De statusregel en elke header zijn in beide hetzelfde, content-length: 132 inbegrepen. Het GET-antwoord gaat verder met de body; het HEAD-antwoord stopt bij de lege regel, en er volgt geen regel meer.
Druk daarna op Check my work. Je server kan de boeken opsommen en HEAD beantwoorden, maar hij kan nog geen enkel boek laten zien. De projectles voegt /books/{id} toe.
Opdracht
Breid handle in reading_server.py uit, zodat HEAD precies krijgt wat GET zou krijgen, zonder de body.
Routeer
HEADzoalsGET: op/booksantwoordenGETenHEADallebei met de. Bewaar het antwoord van elke tak in één
en geef die één keer terug, aan het eind van handle. Zet vlak voor diede body op b""als deHEADis, zodat de regel elk pad dekt, de 404 en de 405 inbegrepen.Laat de headers met
: content-lengthop een antwoord opHEADis de lengte van de body dieGETzou versturen.Beantwoord andere methoden op
/booksmetnot_allowed("GET, HEAD").
Voer python pl_http.py head uit in de GET en HEAD.
Druk daarna op Check my work. Die roept handle aan met eigen states en vergelijkt elk HEAD-antwoord met het GET-antwoord voor hetzelfde doel: voor /books, voor een gecodeerd /books met een query, voor een lege lijst, en voor paden die met 404 antwoorden. Elk HEAD-antwoord moet dezelfde status en dezelfde headers hebben als het GET-antwoord, met content-length gelijk aan de lengte van de body van GET, en een lege body. GET-antwoorden moeten hun body houden, en DELETE, PUT en POST op /books moeten antwoorden met 405 en een header allow die zowel GET als HEAD noemt. Niets uit je terminal wordt beoordeeld, en er wordt geen server gestart.