Chunked content
Förord
Ibland tar det länge att skapa/få fram informationen för en webbsida, och då kan det vara bra att skicka information till användaren redan innan hela sidan är klar. Detta är möjligt genom att använda sej av sk. Chunked transfer i HTTP. Exemplen i denna artikel är skrivna är skrivna i PHP men torde enkelt gå att applicera även på andra språk.
Transfer-Encoding: chunked?
Chunked transfer betyder att datan överförs i bitar. HTTP (hypertext transfer protocol) version 1.1 specifierar att alla som implementerar version 1.1 MÅSTE stöda chunked transfer. Detta innebär i praktiken att alla nutida servrar och klienter stöder denna teknik.
Skillnad mellan vanlig överföring och bitvis överföring
Skillnaden hittas bland headersen, bitvis överföring specificerar Transfer-Encoding: chunked men ingen Content-Length. Medan "vanlig överföring" kräver att en korrekt specificerad Content-Length header finns specificerad, detta för att "persistenta uppkopplingar" (persistent connection) skall kunna fungera.
Vad händer bakom kulisserna?
Det fungerar som så att kontakten mellan klient och server hålls uppe tills all data är skickad. I stället för att servern skickar hela sidan på en gång, så skickas den i lämpliga delar.För att veta var bitarna börjar och slutar så måste längden på innehållet vara specificerat. Normalt används en Content-length header.
Men eftersom headers per definition ska komma före datan, så kan vi inte skicka längden på data som vi inte vet längden på innan vi skickat all data, innan vi börjat skicka data.
I stället kodas varje del så här:
antal_bytes_hexadecimalt CRLF
data CRLF
Där CR står för ascii tecknet carriage return (0xD) och LF står för ascii tecknet line feed (0xA). Den sista biten meddelas med hjälp av en bit (chunk) med längden 0.
Potentiella användningsområden
Detta är inte en fullständig lista, men kan kanske ge några ideer:- Chatt
- Uppdatera en "progressbar" innan sidan är klar att visa
- Visa delar så fort dom är klara på en sida som hämtar information från olika nätsidor, typ "multi-sök sida".
- ...
Ja, ja.. vi vill se ett exempel nu!
Vi tänker oss att vi kommer på den (befängda) idén att göra en klocka m.h.a. denna teknik. Vi tänker oss då att vi varje sekund skicka en kodsnutt som uppdaterar en "klocka" på en webbsida. Naturligtvis är detta inte ett vettigt användningsområde, eftersom det finns enklare sätt att lösa det hela på, samt att varje klient kräver en konstant ansluting (persistent connection) till servern. Men detta är som sagt endast ett exempel.Vi vill använda följande html sida som bas för klockan:
Klocka
Klocka
??:??:??
För att uppdatera innehållet i div:en med id "klocka" använder vi oss av följande teknik. Vi använder standardenligt getElementByIdför att hitta vår div. Därefter använder vi oss av en icke-standard property .innerHTML (som dock stöds av "alla" browsers) för att ändra på innehållet.
document.getElementById("klockan").innerHTML = ;
Alltså, för att vår klocka ska fungera som väntat bör vi varje sekund skicka en kodsnutt som m.h.a. ovanstående javascript uppdaterar "klockan" (dvs. div:en med id "klockan")
set_time_limit(0);
while (true) {
sleep(1);//sov 1 sekund så att vi skickar en kodsnutt i sekunden (ungefär)
print "<script type='text/javascript'>\r\n";
print "document.getElementById('klockan').innerHTML = '".date("H:i:s")."';\r\n";
print "</script>\r\n";
//töm buffern och skicka allt till klienten NU.
flush();
//om ifall du har output buffering påkopplat kan även följande behövas
//ob_flush();
?>
}
På tråden kommer överföringen av en del alltså att se ut som följande, (längden av datan från och med <script..> till och med \r\n efter </script> är 104 tecken, dvs 68 hexadecimalt)
68\r\n
<script type='text/javascript'>\r\n
document.getElementById('klockan').innerHTML='hh:mm:ss';\r\n
</script>\r\n\r\n
Den sista delen ser ut så här:
0\r\n
Gotchas..
- Vissa källor tyder på att browsern vill ha åtminstone 256bytes / chunk innan den börjar rendera, detta har jag inte märkt av men kan vara bra att hålla i minne ändå.
- Dessutom kan man inte skicka data hur som helst inuti en tabell, åtminstone en rad (
.. ) bör man skicka. - Som nämts flera gånger tidigare upprätthålls kontakten mellan klient och server ända tills hela sidan är skickad.
Det var allt.
PS. Som vanligt mottages kritik, tips, förslag osv.. med tacksamhet!
0 Kommentarer