Geschrieben von

HTTP-Caching

Performance

Heutzutage besitzen alle Browser einen HTTP-Cachespeicher, wo Ressourcen beim ersten Seitenauruf zwischengespeichert werden können, damit diese beim wiederholten Seitenauruf nicht nochmal vom Server angefordert werden müssen. Das beschleunigt die Seitenladegeschwindigkeit. Webentwickler müssen nur sicherstellen, dass die richtigen Angaben für den Browser gemacht werden.

Fordert der Browser beim Server eine HTML-Seite an, werden vom Server verschiedene Angaben im HTTP-Header mitgegeben. Darunter sind auch Caching-Anweisungen zu finden. Ein HTTP-Header kann beispielsweise folgendermaßen aussehen:

200 OK
Content-Length: 1024
Cache-Control: max-age=80
ETag: "a456rrt"

Caching-Angabe: ETag

Im ETag (steht für Entity-Tag) wird ein Validierungstoken vom Server beim Erstaufruf der Ressource erzeugt und mitgesendet. Dieser Wert ist sozusagen der Fingerabdruck einer Datei. Die ETag-Angabe wird lokal im Cache abgespeichert. Im obigen Beispiel lautet die Angabe ETag: „a456rrt“. Dieses Tag wird vom Browser benutzt um zu vergleichen, ob sich die lokal abgespeicherte Datei verändert hat oder ob diese noch gleich ist. Sollte die gleiche Ressource vom Browser nochmal angefordert werden, wird dieses Token mitgesendet. Dies geschieht in der Form If-None-Match: „a456rrt“. Auf Serverseite wird das mitgeschickte Token mit dem Aktuellen verglichen. Stimmen die Werte überein, muss die Ressource nicht nochmal geschickt und geladen werden. Durch die identische Zeichenkette weiß der Browser, dass die Ressource nicht geändert wurde. Dadurch wird die Datei lokal abgerufen. Vom Server wird dabei „304 Not Modified“ zurückgesendet.

Falls sich die Datei geändert hat, würde auf Serverseite ein anderer Token im ETag stehen. Beim Abgleich würde der Browser erkennen, dass diese nicht identisch sind und müsste daher die Ressource neu laden.

Den gesamten Vorgang übernimmt der Browser selbst. Hier muss nur von den Server-Zuständigen sichergestellt werden, dass der Server die Token bereitstellen kann. Beim Apache-Server braucht man Zugriff auf die Apache-Config. Mit dem Eintrag FileETag All in der httpd.conf kann man diese Methode aktivieren. Alternativ kann man den Eintrag auch in der .htaccess setzen.

Welche Werte sollten beim ETag eingesetzt werden?
Details können hier nachgelesen werden. Zusammengefasst kann man sagen, dass als ETag-Werte folgende Angaben in Betracht kommen:

  • INode: Hierbei handelt es sich im die Dateinummer im System. INode sollte eher nicht als ETag verwendet werden, da bei einem CDN die Nummer einer Datei unterschiedlich sein kann. Grund hierfür ist, dass mehrere Server zum Einsatz kommen, wodurch eigene Nummern generiert werden.
  • MTime: Hier wird das Datum und die Uhrzeit der letzten Änderung herangezogen.
  • Size: Hier wird die Dateigröße als ETag herangezogen.

Wann macht die Verwendung von ETags keinen Sinn?
Bei statischen Dateien oder Dateien, die sich kaum ändern. Beispiel: Bilder. In diesem Fall würde der Einsatz des ETags nur unnötigen Aufwand für den Browser bedeuten. Stattdessen ist es besser den max-age (mehr dazu weiter unten) hoch anzusetzen (z.B. für ein Jahr). Um zu verhindern, dass das ETag mitgegeben wird, setzt man FileETag None ein.

Caching-Angabe: Cache-Control

Cache-Control wurde mit HTTP/1.1 eingeführt und ersetzt bisherige Angaben wie „Expires“. Mit den Cache-Control-Anweisungen können wir dem Server und Browser mitteilen, wie und wie lange eine Ressource im Cachespeicher abgelegt werden kann. Dadurch können wir bei erneuten Anfragen der gleichen Datei Requests minimieren, um unnötige Datenübertragungen zu vermeiden. In unserem obigen Code-Beispiel ist Cache-Control daran zu erkennen:

Cache-Control: max-age=80
Folgende Angaben sind innerhalb Cache-Control möglich:

  • no-cache und no-store: no-cache gibt an, dass der Browser die im Cache gespeicherte Version nicht direkt verwenden darf, sondern vorher einen Abgleich mit dem Server machen muss. Liegt ein ETag vor, wo Browser und Server vergleichen können, wird ein Download vermieden. no-store ist hingegen strikter: Es verbietet das Setzen einer Datei in den Cache.
  • Öffentlich oder privat: Mit „public“ (öffentlich) gibt man an, dass die Ressource von jedem Cache zwischengespeichert werden kann. Mit „private“ gibt man an, dass die Ressource nur vom Cache eines einzelnen Nutzers zwischengespeichert werden darf (z.B. Seite mit privaten Informationen).
  • max-age: Gibt an, wie lange die Ressource zwischengespeichert werden kann. „max-age=120“ gibt z.B. an, dass die Ressource 120 Sekunden zwischengespeichert werden kann.

Für die einzelnen Files kann man sich an folgende Faustregeln halten:

  • Bei Bildern wie png, jpg, gif, etc. kann ein max-age von einem Jahr gewählt werden, da sich diese Dateien in der Regel kaum ändern
  • CSS-Dateien können sich recht schnell ändern, daher sollte man hier ein max-age von 1 Woche wählen (oder auch 1 Monat; Rücksprache mit Frontend-Team sinnvoll)
  • ico-Dateien (Favicons) ändern sich in der Regel kaum und können auf ein Jahr gesetzt werden
  • JS-Dateien können auf 1 Monat gesetzt werden (außer es wird viel und laufend an JavaScript gearbeitet, dann empfiehlt sich eine kürzere max-age-Dauer)

Mögliche Probleme beim Caching vorbeugen

Wenn Caching für Dateien aktiviert ist und diese für eine bestimmte Zeit zwischengespeichert werden, dann greift der Client auf diese Dateien innerhalb der definierten Zeit zurück. Was aber, wenn sich in der Zwischenzeit die zwischengespeicherte Datei geändert hat? Z.B. hat sich das Bild für einen Artikel oder es haben sich Angaben im CSS geändert, die für alle Nutzer live sichtbar sein sollten.

Nun ist es so, dass die aktualisierte Datei und Version erst bei folgenden Szenarien selbstständig live verfügbar ist:

  • max-age läuft ab und der Browser muss sich die Ressource vom Server neu holen
  • Der Cache des Nutzers wird gelöscht (z.B. manuelles Löschen)

Es kann also vorkommen, dass Nutzer verschiedenen Versionen der Webseite zu sehen bekommen, da einige in der Zwischenzeit ihren Cache löschen und andere wiederum nicht.

Wie bekommen wir es aber trotzdem hin, das Caching beizubehalten und Updates immer sofort sichtbar zu machen?
Wir müssen die URL der aktualisierten Datei ändern. Sobald sich der Dateiname ändert, wird der Browser automatisch dazu gezwungen, die Ressource neu herunterzuladen. Hierzu ist es sinnvoll sich im Vorfeld bei Dateien wie CSS, JavaScript oder Bildern Gedanken zu einem Dateinamen-Konzept zu machen. In Betracht kommt bspw. der Zusatz zur Versionsnummer oder das Datum der Aktualisierung.

Statt style.css wird dann style.v135.css oder statt script.js wird script.v14.js. Mit diesem Vorgehen ist es auch möglich CSS- und JS-Dateien lange Gültigkeitsdauern in max-age zu definieren, da ein Fingerabdruck im Dateinamen hinzugefügt wird.

Last modified: 26. Januar 2019