Teile der Website cachen lassen

16.03.2010, 22:44

Kürzlich habe ich den TrafficScanner um die Anzeige von Cache-Möglichkeiten erweitert. Dabei geht es darum die HTTP-Header, welche dem Browser die "Erlaubnis" geben eine Ressource zu cachen, aufzuzeigen. Das ganze kommt daher, dass der im Grunde effizienteste Weg, Traffic zu sparen, das Caching ist. Je mehr der Client bei einem erneuten Aufruf der Webseite aus seinem Cache lädt, desto weniger Traffic ist vonnöten. Entsprechend ist die Geschwindigkeit auch höher.
Allerdings lässt sich nur schwer alles cachen. Eine dynamische Seite darf schon gar nicht gecached werden, da sich der Inhalt ja bei jedem Aufruf (oder anderweitig häufig) ändern sollte.

Doch erst mal beim eigentlichen anfangen: Der Webserver kann dem Clienten z.B. über den HTTP-Header "Expires" mitteilen, ob und wie lange bzw. bis wann er die Ressource zwischenspeichern soll. Bei statischen Bildern ist diese Zeitspanne entsprechend hoch angesetzt, da sich diese eigentlich nie mehr ändern werden und daher bis zum nächsten Zeitalter im Cache gespeichert bleiben können (Beispiel). Aber auch bei dynamischen Bildern kann ein solcher Header gesetzt werden, wenn sie sich nicht bei jedem Aufruf ändern (Beispiel). Eine solche Grafik darf problemlos bis am Ende des Tages im Cache bleiben.
Ein bisschen problematischer ist die Verwendung des Expires-Headers bei CSS- und JavaScript-Dateien, da sich diese Dateien aus Sicht des Clients unerwartet ändern können und die entsprechende Website möglicherweise fehlerhaft dargestellt wird, wenn beispielsweise die CSS-Datei noch die alte aus dem Cache ist, doch die HTML-Datei für die korrekte Darstellung ein neueres CSS erfordert. Dies soll aber nicht heissen, dass man hier kein Caching über den Expires-Header einrichten soll, denn ein paar Tage dürften solche externen Dateien schon im Cache bleiben. Dasselbe gilt auch für HTML-Dateien oder pseudo-dynamische PHP-Seiten, die nicht alle 15 Minuten einen anderen Inhalt zeigen, welche daher beim zweiten oder dritten Aufruf auch noch aus dem Cache geholt werden können (Beispiel, ändert nur nachts um 3 oder bei einem neuen Blog-Eintrag).

Um das Problem mit dem richtigen Aktualisierungszeitpunkt zu umgehen, stehen die HTTP-Header "Last-Modified" und "ETag" zur Verfügung. Hierbei kann der Client den Server anfragen, ob seine Datei im Cache noch aktuell ist oder ob bereits eine neuere Version der Ressource existiert. Wenn die gespeicherte Datei im Cache noch die aktuelle ist, muss die Datei nicht vom Server heruntergeladen werden, womit man sich den einen Request zwar nicht erspart, dafür aber den Traffic (Beispiel). Der Vorteil dieser Methode ist, dass die Ressource (nur) dann aktualisiert wird, wenn sie es auch muss. Der Nachteil wiederum ist, dass wie gesagt trotzdem jedes Mal ein Request an den Webserver geht, was beim "Expires" nicht so ist.

Somit empfiehlt es sich, den Expires-Header für kurzfristiges Caching zu setzen und den Last-Modified- und ETag-Header fürs längerfristige zu benutzen.

Aber wie sorgt man nun für diese Angaben bzw. für deren Funktionalität?
Der Expires-Header und das Äquivalent "Cache-Control: max-age" lässt sich ganz einfach über die .htaccess steuern, wenn das Modul "mod_expires" vorhanden ist:
ExpiresActive On
ExpiresDefault "access plus 4 weeks"
ExpiresByType image/png "access plus 3 months"
ExpiresByType text/css "access plus 7 days"
Für mehr zu mod_expires siehe Dokumentation.

Mit PHP lässt sich das ebenfalls simpel umsetzen:
<?php
$maxAge 
60*60*24*14// max. Cache-Dauer in Sekunden
header('Expires: '.gmdate('D, d M Y H:i:s'time()+$maxAge).' GMT');
header('Cache-Control: max-age='.$maxAge);
?>

Die Geschichte mit dem Last-Modified- und dem ETag-Header ist vergleichsweise komplizierter. Allerdings macht da einem der Webserver oft einen gefallen und übernimmt die Funktion von Anfang an für statische Dateien wie Bilder, CSS und JavaScript. Wenn nicht, kann man mit einem Befehl in der .htaccess ein bisschen nachhelfen:
FileETag All
Auch hier lässt es sich mit PHP umsetzen, doch ist es wie gesagt ein bisschen komplizierter, da hier nicht nur einfach ein HTTP-Header gesendet werden kann, sondern auch die Funktionalität nachprogrammiert werden muss: If-Modified-Since nachbauen.
Zu dieser Anleitung sei noch angemerkt, dass der Request-Header "If-Modified-Since" das Gegenstück zu "Last-Modified" ist und der "If-None-Match" das Gegenstück zum "ETag".

Ob die HTTP-Header korrekt eingefügt sind und funktionieren, lässt sich mit dem Tool GetHeader überprüfen.
 


Andere Einträge


Kommentare

#1
von Michael Freund am 23.02.2011, 15:17
PageSpeed (s. google webmaster-tools) empfiehlt ausdrücklich, den ETag-Header abzuschalten und statt dessen nur den Expires-Header zu verwenden! Dazu muß folgendes in der .htaccess stehen.

FileETag none

Mehr zu Page-Speed unter:

http://code.google.com/intl/de-DE/speed/page-speed/download.html

#2
von handynetz24 am 22.03.2011, 07:33
Das ist mal endlich eine leicht verständliche Darlegung von Website cachen – super. Auch die Tipps zu weiteren Quellen sind Toll, danke!