Kommuniser med HTTP

Rails har nå endelig fått støtte for bruk av ETags for å avgjøre om innhold har endret seg eller ikke. ETags er eldgammel teknologi; som så mange ting er det først nå vi begynner å forstå hvor nyttig HTTP-standarden faktisk er.

ETags er en ganske enkel måte en HTTP-klient og HTTP-server kan gi hverandre hint om en ressurs har endret seg siden sist man brukte den eller ikke. Rent skjematisk er prosessen slik:

  • HTTP-klienten, for eksempel nettleseren din, ber om en ressurs – for eksempel http://host.example/people
  • HTTP-serveren henter ut denne ressursen, for eksempel fra en database eller filsystemet. Den bruker deretter en mekanisme den velger selv til å unikt identifisere dette innholdet, som regel en sjekksum. Sammen med dataene den sender tilbake til klienten sender den denne sjekksummen som HTTP-headeren ETag
  • HTTP-klienten “husker” denne sjekksummen, og sender den med tilbake til serveren neste gang den spør om samme ressurs, denne gangen som HTTP-headeren If-None-Match. På denne måten forteller klienten serveren at den bare er interessert i innholdet dersom det har endret seg siden denne sjekksummen ble laget
  • HTTP-serveren henter ut ressursen på samme måte som før, og genererer samme sjekksum. Deretter sjekker den om sjekksummen klienten sendte er den samme som sjekksummen innholdet har nå. Hvis innholdet har endret seg sender serveren innholdet på samme måte som før, og sender med den nye sjekksummen som ETag-headeren
  • Hvis innholdet derimot ikke har endret seg siden sist sender HTTP-serveren en 304 Not Modified-header og ingen data i responsen. HTTP-klienten vet da at innholdet den fikk sist, som den typisk har lagret i cache, fortsatt gjelder.

Denne prosessen gjør ikke alltid lasten på serveren mindre. I noen tilfeller, for eksempel når man har en HTTP-server som henter filer fra filsystemet, vil serveren kunne beregne sjekksummen med relativt lav kostnad. I eksempelet med filer kan man bruke tidspunktet fila sist ble endret, og dermed slippe å lese inn fila. I andre tilfeller må serveren faktisk hente innholdet og beregne sjekksummen på nytt, noe som gir omtrent samme belastning på serveren som før.

Imidlertid er det to andre faktorer som spiller inn: tiden det tar å transportere selve dataene tilbake over nettet og tiden det tar for klienten å tolke innholdet. Det tar tid å parse HTML, det tar tid å parse CSS, det tar tid å parse XML og javascript.

En slektning: If-modified-since

En lignende situasjon som der man bruker ETags er der klienten selv kan angi overfor serveren kriterier som skal tilfredsstilles for å avgjøre om innholdet har endret seg eller ikke. Til dette kan man bruke headeren If-modified-since. Om du for eksempel lager et mailsystem der klienten kan hente nye meldinger over HTTP kan man tenke seg at klienten sjekker etter nye meldinger hvert femte minutt. Vi kan da tenke oss dette scenariet:

  • Første gang klienten spør etter nye meldinger returnerer serveren alle meldinger som ligger i innboksen
  • Klienten “husker” så dette tidspunktet inntil den skal hente meldinger igjen
  • Når klienten fem minutter seinere sjekker etter nye meldinger sender den HTTP-headeren If-modified-since med tidspunkt for siste sjekk som verdi
  • Serveren kan da sjekke om det er kommet nye meldinger til denne brukeren siden sist. Hvis det ikke finnes nye meldinger svarer så serveren med en 304 Not Modified, og vi sparer igjen nettverkstrafikken og parsing av responsdataene

For en vanlig webapplikasjon, der klientene er vanlige nettlesere, er antakelig ETags den enkleste løsningen. En nettleser skal nemlig sende med informasjon om siste ETag den fikk, og man legger dermed ansvaret for å avgjøre om innholdet er endret til serveren. For en applikasjon der man kan styre betingelsene fra klienten, for eksempel der klientene er et API, gir imidlertid If-Modified-Since-headeren mer finkornet kontroll. Om vi skjematisk sammenligner de to modellene kan det se slik ut:

ETags

  • Klienten: jeg er interessert i innholdet /people, sist jeg hørte fra deg var sjekksummen for dette innholdet “abscder90”
  • Serveren: OK, innholdet du har er fortsatt gyldig

If-Modified-Since

  • Klienten: gi meg innholdet /people bare hvis det har endret seg siden klokka sju imorges
  • Serveren: OK, innholdet har ikke endret seg

Hvis vi for eksempel tenker oss at Twitter hadde støttet If-Modified-Since-headeren kunne en API-klient spurt etter nye meldinger siden et gitt tidspunkt. Serveren kunne så hatt en kolonne i sitt User-objekt som holder rede på sist en ny melding ble mottatt. Ved hjelp at en enkelt SQL-spørring kunne serveren så avgjort om den kan sende en 304 Not Modified eller om den må inn og hente nye meldinger fra databasen. Om man i tillegg tar denne litt lenger kunne vi tenke oss at dersom innholdet har endret seg sender serveren bare det nye innholdet tilbake. HTTP-spesifikasjonen har en egen header til dette formålet: If-Range. Med If-Range kan man angi både en ETag og en dato. På denne måten angir klienten at den har en delvis representasjon av innholdet, og at den bare er interessert i det som er nytt siden sist. Serveren skal da svare med 206 Partial content header, sammen med endringene.

Det er bra at Rails har fått støtte for ETags, men dette er bare begynnelsen. HTTP-spesifikasjonen ble plutselig langt mer interessant lesning enn jeg hadde tenkt meg.


Gravatar-aktivert. Les mer om gravatar.
E-postadressen vil ikke vises på siden