HTTP cachování
Školení, která pořádám
PHP standardně neposílá žádné hlavičky, které by umožňovaly cachování (Cache-Control, Expires nebo Last-Modified). Pokud přesně víme, kdy vygenerovaná stránka vyprší (např. pokud vydáváme články jednou denně), je nejlepší posílat hlavičku Expires a o nic dalšího se není třeba starat – proxy cache nebo prohlížeče si o stránku řeknou až po vypršení tohoto data. Mnohem častější případ ale je, kdy nemůžeme přesně říct, kdy stránka vyprší (protože na ní máme např. diskuse), ale dokážeme alespoň určit, kdy byla naposledy změněna. V tom případě se vyplatí posílat hlavičku Last-Modified:
<?php
$last_modified = mysql_result(mysql_query("
SELECT UNIX_TIMESTAMP(GREATEST(clanky.zmeneno, MAX(diskuse.vytvoreno)))
FROM clanky
LEFT JOIN diskuse ON clanky.id = diskuse.clanek
WHERE clanky.id = " . intval($_GET["id"])
), 0);
if ($_SERVER["HTTP_IF_MODIFIED_SINCE"] && $last_modified <= strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
header("HTTP/1.1 304 Not Modified");
exit;
}
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $last_modified) . " GMT");
?>
Poslání této hlavičky má dva příjemné následky:
- Pokud proxy cache vyhodnotí, že byl objekt změněn dávno a je tudíž nepravděpodobné, že by byla k dispozici jeho nová verze, tak nás s požadavkem vůbec neobtěžuje.
- Pokud má prohlížeč nebo proxy cache k dispozici starší verzi požadovaného dokumentu, pošle nám hlavičku If-Modified-Since, na základě které se můžeme rozhodnout, zda pošleme aktualizovanou stránku nebo zda prohlížeči hlavičkou 304 sdělíme, že jeho verze stále platí.
Pokud o expiraci nevíme nic, je možné posílat hlavičku Cache-Control s hodnotou max-age
a tím zaručit, že stránka se bude aktualizovat např. nejpozději po 10 minutách. Touto hlavičkou lze ovlivnit i další nastavení cachování.
Proč vůbec cachovat?
- Zrychlí se odezva stránek.
- Sníží se objem přenášených dat, za který se obvykle platí.
- Sníží se zátěž serveru. Aby platil tento bod, musí být zjištění informací pro cachování nenáročné, jinak se zátěž serveru může i zvýšit. V uvedeném příkladě by proto bylo lepší z dotazu tabulku
diskuse
vyřadit a při vložení nového příspěvku aktualizovat rovnou tabulku clanky
. Tuto tabulku je potom možné aktualizovat i v případě odstranění diskusního příspěvku, což by v uvedeném příkladě způsobilo špatnou funkci cache.
Radost z kešování nám mírně můžou zkazit prohlížeče, které se chovají jinak, než by bylo ideální:
- Ideální chování
- Podle mě by se prohlížeč měl ptát serveru na novou verzi dokumentu, pokud
(now - cached_time) > x * (now - Last-Modified)
, kde x
může být řekněme kolem 0.1.
- Firefox
- Pomocí browser.cache.check_doc_frequency lze nastavit, podle jakých pravidel se mají nové verze dokumentů kontrolovat. Výchozí hodnota 3 je přijatelná v tom, že se rozhoduje na základě hlavičky Expires, jinak se zeptá serveru.
- Internet Explorer
- Chování lze ovlivnit pomocí dialogu Dočasné soubory Internetu | Nastavení, výchozí volba Automaticky zajišťuje podle nápovědy také přijatelné chování (předchozí relace nebo předchozí den, časem po ještě delší době).
- Opera
- Opera se chová ze všech prohlížečů nejhůř. Chování lze sice nastavit zvlášť pro stránky, obrázky a ostatní data, ale výchozí hodnota Každých 5 hodin je pro často se měnící dokumenty zcela nepoužitelná. Kromě toho prohlížeč nabízí už jen jiné časy a volby Vždy a Nikdy, automatické rozhodování ostatních prohlížečů chybí. Pro správnou funkci je použitelný buď krátký čas nebo volba Vždy, což zase může zbytečně zdržovat.
Podrobnější informace o cachování lze nalézt v překladu Kešovací návod od Yuhůa.
Přijďte si o tomto tématu popovídat na školení Výkonnost webových aplikací.
Diskuse
Lukáš:
HTTP NEcachování
Jak přinutit proxy cache a prohlížeče aby nikdy nic necachovali? Stačí hlavičky:
Last-Modified: Sat, 01 Jan 2000 00:00:00 GMT
Cache-Control: no-cache, must-revalidate
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Potřebuji to do jednoho B2B projektu, který běží na veřejném serveru a občas narážím na problém, že některé podniky mají špatně nastavené firemní proxy servery a nebo i uživatelé počítače a zobrazuje se jim něco, co už neplatí.
Leo:
"občas narážím na problém, že některé podniky mají špatně nastavené firemní proxy servery a nebo i uživatelé počítače a zobrazuje se jim něco, co už neplatí."
S tim obecne nic nenedalete - posilanim http hlavicek nemuzete prerazit nastaveni (spatne nastaveni) klienta. Ale jinak staci
Expires: v minulosti
Cache-control: no-cache,no-store,max-age=0,must-revalidate;
Pragma: no-cache;
S Last-modified se pak uz nemusite obtezovat. Leo
Libor Tvrdík:
Máte pravdu. Jediné řešení jak obejít toto nastavení je měnit URL. Tento problém jsem řeši u mobilních telefonů (WAP), kde kešování dosahovalo neskutečných rozměrů.
Do URL jsem vkládal náhodný parametr s náhodnou hodnotou. Stránka se tvářila pokaždé jinak, jen bylo potřeba upravit všechny formuláře.
Např:
http://php.vrana.cz/http-cachovani.php?TMDl4x5=94kP3Frb
Libor Tvrdík:
http://... není URL? Viz věta pod příspěvkem ...ale PHP kód uzavřený do
<?php ?> bude zvýrazněn a URL budou převedeny na odkazy...
závorky patří takhle: (PHP kód uzavřený do <?php ?> bude zvýrazněn) a (URL budou převedeny na odkazy). Prohodil jsem pořadí klauzulí, ať to je jednoznačné.
Andrew:
Také jsem tenhle trik používal u WAPu (inspirován panem Koskem), ale normálně mi to přijde hloupé - od čeho jsou hlavičky.
Libor Tvrdík:
Aby je proxy ignorovaly? ;) Uznávám ale že je to přinejmenším nepohodlné.
mic362:
Mam takový problem, server mi nevraci tuto hodotu - $_SERVER["HTTP_IF_MODIFIED_SINCE"];
Je potřeba nějaké spec. nastavení?
pekne. problem cachovani jsem yrovna resil, tenhle priklad urcite vyuziju. diky moc
David:
Ahoj, zkouším si vaše příklady a zatím mi vše funguje. Nyní jsem narazil na problém v cachování. Používám webhosting:
http://www.savana.cz/ a myslím si, že tam mají nějaké omezení pro cachování, nejsem ale odborník, je to můj názor. K=od mi vždy selže. Lze si ověřit, za tam je nějaké omezení, nebo je chyba u mne? Děkuji
Diskuse je zrušena z důvodu spamu.