Tim Tepaße: Kontrolle über das Caching bei Amazon S3

Beitrag lesen

Hallo Rainer,

Ich würde gerne wissen, ob man es auch umgekehrt beeinflussen kann, also dem Browser das Cachen von Bildern "empfehlen" kann.

Empfehlungen zum Cachen sind ja in HTTP eingebaut und Browser berücksichtigen diese Empfehlungen auch. Einen guten Überblick, wie das auf der technischen Ebene genau funktioniert bietet Mark Nottinghams Caching Tutorial. Ich fasse mal zusammen: Für Ressourcen, die sich eh nie ändern, sollte man entweder einen Expires-Header mit einem Datum weit in der Zukunft setzen (der HTTP-Standard empfiehlt ein Jahr) oder aber noch besser den Cache-Control-Header mit einer möglichst langen Ablaufzeit (spezifiziert in Sekunden) zu setzen. Der Cache-Control-Header ist besser für Amazon (und prinzipiell besser); man muß einfach nicht einen neuen Expires-Header-spezifizieren, wenn der Termin in der Zukunft abgelaufen ist.

Noch kürzer: Du mußt diesen Header in die Antworten auf HTTP GET von Amazon S3 reinkriegen:

Cache-Control: max-age=2678400

2678400 Sekunden sind so ungefähr ein Monat; eine schon recht lange Zeitangabe finde ich.

Hintergrund: ich nutze Amazons S3 Service um Bilder nebst kleinen Vorschaubildern zu hosten. (...)
Diese Vorschaubilder werden nämlich sehr oft aufgerufen und fast die gesamten Kosten des S3 Services entstehen nicht durch das Speicher- oder Trafficvolumen, sondern durch die vielen Abfragen.

Mal neugierig gefragt: Lohnt sich das denn wirklich? Ich meinte seit der Preisänderungen damals, dass S3 sich eher mehr für größere Dateien lohnt denn für viele kleine Ressourcen. In diesem Thread im S3 Forum scheint man derselben Meinung zu sein.

Und gäbe es eine einfache Möglichkeit (Meta-Tags, Javascript, Header der Website [nicht Header beim Bildabruf]), über die Website das Caching für die darin befindlichen Bilder auch bei kleinen Bildern zu beeinflussen?

Header beziehen sich im Prinzip immer nur auf die Ressource, mit der sie ausgeliefert werden, insofern ist es viel geschickte wie oben schon gesagt einen zusätzlichen Header zu den Thumbnail-Antworten von S3 hinzuzufügen. Bei Webservern wie Apache, die meist einfach das Dateisystem abbilden, setzt man solche Metadaten wie Header in Konfigurationsdateien wie .htaccess (und z.B. der Direktive Header). Bei Amazon S3 geschieht das Speichern der Daten nicht über eine Dateisystemschnittstelle sondern über HTTP – und dort muss man die Metadaten mitschicken.

S3 hat ja eine auf dem Prinzip REST basierende Schnittstelle; das in diesem Kontext soviel bedeutet wie »die Möglichkeiten von HTTP voll ausnutzen«. Speichert man eine Textdatei, sieht der HTTP Request ungefähr so aus:

PUT /dingsbums HTTP/1.1
  Content-Length: 12
  Host: beispielbucket.s3.amazonaws.com
  Date: Thu, 06 Dec 2007 06:00:00 GMT
  Authorization: AWS Zugangsschluessel:Signatur
  Content-Type: text/plain
  Expect: 100-continue

Beispieltext

Die Methode PUT ist in HTTP so spezifiziert, dass der Server diverse Header im Request auch als mögliche Header in der Response des zu erstellenden, updatenden Ressource nutzen kann. S3 nutzt diese Möglichkeit z.B. für die beliebigen nutzerspezifischen Metadaten, mit denen man die gespeicherten Objekte ausstatten kann. Aber laut dem Abschnitt zu PUT im Developer-Guide gilt dies auch für diverse generelle HTTP-Header, u.a. auch Cache-Control. Ein Beispiel-PUT mit eingebautem zeitlosen Caching sähe also so aus:

PUT /hurz HTTP/1.1
  Host: beispielbucket.s3.amazonaws.com
  Date: Thu, 06 Dec 2007 06:00:00 GMT
  Authorization: AWS Zugangsschluessel:Signatur
  Content-Type: text/plain
  Content-Length: 5
  Expect: 100-continue
▶ Cache-Control: max-age=2678400
  x-amz-meta-author: Hape Kerkeling
  x-amz-meta-kategorie: Dichtkunst

Hurz!

Also: Einfach nur den passenden Cache-Control-Header im speichernden HTTP-Request unterbringen. Meine ich. Ich hab's jetzt mangels S3-Zugang nicht ausprobiert. Hatten die nicht mal eine Sandbox, in der man das ausprobieren konnte, ohne gleich Kreditkartendetails rüberzurücken oder irre ich mich da?

Solltest Du eine Bibliothek nutzen: Beim nicht sehr intensiven Drüberschauen scheinen die meisten wohl eine Möglichkeit zu haben, Header bzw. Metadaten zu setzen. Ich würde sie aber trotzdem erstmal ausprobieren. Die Header für die nutzerspezifischen Metadaten werden ja mit dem Präfix "x-amz-meta-" ausgestattet; ein schlampiger Programmierer könnte das einfach generell machen, ohne eine Ausnahme für die spezifischen nicht bepräfixten HTTP-Header zu machen.

Solltest Du eine Bibliothek nutzen, die die SOAP-API nutzt: Laut Dokumentation gibt es dort das Element <Metadata> in der PutObject Operation und laut Beispielen wird es auch für HTTP-Header wie Content-Type genutzt, könnte also wie bei den Headern der REST API funktionieren. Allerdings wird hier im S3 Forum gesagt, dass es bei SOAP nicht funktioniert. Vielleicht ist das wieder implementierungsabhängig → einfach ausprobieren.

Tim