Přinášíme vám další díl o komunikaci mezi stránkou a serverem. Tentokrát se podíváme na načítání webových stránek přes nový protokol HTTP/2, který snad již brzy nahradí 15 let starý protokol HTTP.

Komunikace webové stránky se serverem začíná už ve chvíli, kdy se prohlížeč dostane ke zdrojovému kódu stránky a vyžádá si její externí části (stylopisy, skripty, obrázky, sady fontů atd.). Tento proces je notoricky známý a nebyl by důvod se pouštět do jeho rozboru, kdyby se právě v době psaní tohoto seriálu neobjevila zpráva, že organizace IETF schválila finální podobu nové verze protokolu HTTP. Významnost této novinky asi netřeba nijak zvlášť zdůrazňovat, vždyť HTTP je jedním z pilířů internetové komunikace, žádný web by bez tohoto protokolu nebyl normálně přístupný.

Zpráva o dokončení HTTP/2 nepřišla jako blesk z čistého nebe, dá se spíš říct, že byla nedočkavě vyhlížena. Od vydání poslední verze totiž uběhlo předlouhých 15 let a bylo jasné, že starý protokol dávno přestal vyhovovat. V dnešní době bývá k textovému obsahu stránky připojeno mnoho externích součástí, které by server mohl posílat rovnou s HTML, a tím ušetřit čas a haldu paketů. Pravidla protokolu HTTP/1.1 však toto neumožňují, každý soubor musí být odesílán samostatně a na vyžádání. Pro každou novou žádost v rámci existujícího TCP spojení je nutno vyčkat na vyřízení předchozího požadavku, což způsobuje nezanedbatelné zdržení. Prohlížeče proto navazují až šest paralelních spojení, z čehož zase nejsou nadšeni zejména správci velkých serverů, neboť nadměrný počet spojení blokuje volné kapacity serveru, jak už bylo vysvětleno v minulém dílu. Navíc to stejně nestačí, neboť stránky mívají podstatně více externích součástí. Kromě toho je nezbytné s každým novým připojením znovu poslat HTTP hlavičku, takže je přenášeno více dat, než je nutné, nemluvě o tom, že jsou hlavičky posílány v nekomprimované podobě, a bývají tak někdy delší, než samotná data.

Řešení slučováním

Každý samozřejmě chce, aby se jeho webové stránky načítaly co nejsvižněji, a tak se vymýšlely všemožné způsoby, jak přenos dat aspoň trochu urychlit. Podle výše uvedeného to vypadá, že latence by mohla být řešitelná redukcí počtu požadavků. Této redukce lze dosáhnout tak, že se všechny součásti stránky vsunou do HTML. Jak známo, do HTML se vleze prakticky všechno. Nejen CSS, JavaScript, SVG ale díky pseudoprotokolu data: i rastrové obrázky. Soubor se nejdřív zakóduje v base64:

function encode_file($url, $mime) {
    $contents = file_get_contents($url);
    $base64 = base64_encode($contents);
    return ("data:$mime;base64,$base64");
}

A pak se do zdrojového kódu vloží v místě, kam patří URL.

<img alt="červený křížek" src="<?php print encode_file('red-cross.png','image/png') ?>">

Uskutečnění záměru nemusí vždy znamenat dosažení vytčeného cíle. A v tomto případě jde opravdu o Pyrrhovo vítězství. Zredukování počtu požadavků je krvavě vykoupeno tím, že žádné součásti stránky, takto zamíchané do HTML, se nedají cachovat, takže se pro každou stránku webu zbytečně stahuje kompletní objem dat; procházení takového webu tudíž není zrovna svižné. Pořád ale platí, že je výhodnější stahovat menší počet velkých souborů, než hromadu malých. V praxi se proto slučují malé soubory do větších – slučují se stylopisy, slučují se skripty, dají se sloučit i obrázky (vznikají tzv. CSS sprity).

Řešení pomocí předběžného načítání

Před nedávnem zde vyšel přeložený článek Santiaga Valdarramy, který pojednával o tzv. prediktivním prohlížení – idea byla jednoduchá: mít další stránku připravenou dřív, než uživatel klikne na odkaz, ba ještě před tím, než na něco takového vůbec pomyslí. K dispozici jsou tři možnosti:

  1. rel="dns-prefetch" – předběžné rozřešení jména domény; nevalidní hodnota
  2. rel="prefetch" – předběžné načtení zdroje
  3. rel="prerender" – načtení zdroje a sestavení ještě před použitím; nevalidní hodnota

Je lepší v těchto případech připojit atribut rel přímo k odkazu v obsahu (tag a), než vytvářet link, protože při editaci nebo smazání odkazu se na link může zapomenout, a pak by se zdroj načítal zbytečně. Ze stejného důvodu není moudré z HTML přednačítat zdroje odkazované v JavaScriptu nebo CSS. Ani to nepředstavuje žádný zvláštní přínos, i v JavaScriptu je možné načítat zdroje v předstihu pro pozdější použití, např. obrázek:

var pict2 = new Image(30,30);
pict2.src = "xicht2.png";

Ale zpět k jednotlivým možnostem:

ad a) Lze využít pouze u zdrojů z externích domén, zpravidla to ale dělají prohlížeče sami bez nějakého donucování, takže se tímto opatřením neušetří ani milisekunda.

ad b) Předběžné načtení zdroje je efektivní pouze za předpokladu, že k tomuto zdroji uživatel skutečně přistoupí. Pokud ne, pak tato „optimalizace“ úhrnný workflow procesu jenom zpomalí!

ad c) Tato technika je nejúčinnější (požadovaná stránka je již sestavená, vykreslená, takže se okamžitě zobrazí), zároveň však nejnáročnější. Proto se její využití vyplatí jen tehdy, když se lze spolehnout, že uživatel bude chtít danou stránku vidět. Není žádoucí zahlcovat síť zbytečnými pakety, server nadbytečnými požadavky a především není žádoucí ždímat procesory uživatelů – baterie tabletů, smartphonů, notebooků nemají zázračnou výdrž.

Představené techniky jsou sice za určitých okolností užitečné, ale právě že jen za určitých okolností – rozhodně to není lék na nedostatky HTTP/1.1.

Skutečné řešení – HTTP/2

Že žádná optimalizace nenahradí skutečné řešení, bylo jasné. I v Googlu si uvědomili, že bez zdokonalení HTTP se dál nepohnou. Proto už před několika lety pro své webové služby vyvinuli vlastní protokol s názvem SPDY, který jednak upravoval a jednak doplňoval stávající HTTP/1.1 a stal se předlohou pro HTTP/2.

Z hlediska rychlosti stahování dat je nejdůležitější změnou oproti dřívějším verzím HTTP koncepce multiplexu. Ta umožňuje všechny požadavky vyřizovat souběžně přes jedno TCP spojení, i když samozřejmě existuje určitý limit, který se dá nastavit. HTTP/2 pro každý dotaz vytváří stream. Jednotlivé streamy mají svůj identifikátor, který je přiřazen každému odesílanému paketu. Streamy jsou na sobě nezávislé, což má tu výhodu, že pokud dojde při vyřizování některého požadavku ke zdržení, nezbrzdí to vyřizování ostatních požadavků, takže přenos dat probíhá nerušeně dál. Nicméně závislost mezi streamy je možné explicitně nastavit. Rovněž je možné stanovit prioritu streamů, a dát tak některým informacím přednost před jinými.

Další novinkou, která pomůže urychlit stahování webových stránek je server push. Jedná se o to, že server už nemusí čekat až zvlášť obdrží požadavky na externí součásti stránky a může stránku poslat kompletně se vším, co k ní náleží.

Fundamentální změnou prošel nejenom způsob komunikace ale i podoba samotných dat, která jsou rozčleněna do jednotlivých rámců (frames). HTTP/2 přenáší data ne už v textovém, nýbrž v binárním formátu. A kvůli komprimaci hlaviček byl také vyvinut nový kompresní algoritmus.

V HTTP/2 se počítá s šifrovaným spojením (TLS). Velká debata se vedla o tom, zda má toto šifrování být povinné. Argumenty proti se týkaly jednak toho, že není nutné veškerou komunikaci šifrovat, a jednak toho, že licence nejsou zadarmo a mají omezenou platnost. Proto bylo nakonec rozhodnuto, že šifrování povinné nebude. Reálně to však může dopadnout jinak. Jestli prohlížeče nešifrované spojení nepovolí, tak zbude jen ta druhá varianta. Řešením by mohlo být DANE.

Se zavedením povinného šifrování také hrozí, že tvůrci webových aplikací podlehnou falešné iluzi bezpečí a přestanou být opatrní. Například stále více programátorů sahá po hotových řešeních a neváhá do zdrojového kódu přidat JavaScript z cizího, neprověřeného zdroje.

Resume

Úplný výčet technických předností HTTP/2 by byl dlouhý. Oproti svému předchůdci je zkrátka rychlejší (až dvojnásobně), úspornější a bezpečnější. K tomu všemu může mít ještě jeden neplánovaný přínos – mohl by motivovat vývojáře, aby se příliš nepouštěli do některých problematických optimalizací.

Přechod na HTTP/2 proběhne nejspíš velmi rychle, u nejpopulárnějších webových serverů (Apache, nginx, …) se podpora očekává nejpozději do konce roku. Prohlížeče už HTTP/2 vesměs podporují a už také existují příslušné implementace v programovacích jazycích.

Ze zdrojů

Žádný příspěvek v diskuzi

Odpovědět