Notizen Praxisnotiz
PRAXISNOTIZ · 4. NOVEMBER 2026 · 3 MIN. LESEZEIT
Cache-Busting auf Cloudflare Pages mit einem Inhalts-Hash
Cloudflare Pages hält CSS- und JS-Dateien lange im Browsercache, ein Inhalts-Hash sorgt beim Deploy für Cache-Busting.
Auf Cloudflare Pages blieben nach einem Deploy alte CSS- und JS-Dateien sichtbar, weil alles unter /assets/ mit Cache-Control max-age=14400 ausgeliefert wird. Ein Browser fragt bekannte Adressen deshalb vier Stunden lang nicht neu ab. Ich löste das mit Cache-Busting, bei dem ein Inhalts-Hash die Adresse jeder geänderten Datei verändert.
Die Kopfzeile blieb alt
Am 27. Juli 2026 hatte ich eine Änderung an der Kopfzeile deployt und sah sie danach nicht. Auffällig wurde das am Sprachknopf, der weiterhin in Arial erschien. Auch eine Leiste blieb 60 Pixel hoch, obwohl die neue Fassung 62 Pixel vorsah.
Der Server lieferte zu diesem Zeitpunkt längst die neue Fassung. Im Browser blieb jedoch die zuvor geladene Datei aktiv. Der Grund lag in max-age=14400. Diese Angabe erlaubt dem Browser, die Antwort vier Stunden lang aus seinem Cache zu verwenden, ohne die Adresse erneut beim Server abzufragen.
Damit war auch klar, weshalb weitere Deploys das sichtbare Ergebnis nicht sofort änderten. Solange der Dateiname und der Verweis darauf gleich blieben, hatte der Browser keinen Anlass für eine neue Anfrage.
Die Headers-Datei griff nicht
Mein erster Versuch führte über eine _headers-Datei. Cloudflare dokumentiert dieses Verfahren unter Cloudflare Pages, Headers. In meinem Projekt lag jedoch auch eine _worker.js. Ein Worker ist Code, der Anfragen verarbeitet und Antworten erzeugt.
Sobald eine _worker.js im Projekt vorhanden ist, wendet Pages die Dateien _headers und _redirects nicht an. Das war beim Deploy schwer zu erkennen, weil Wrangler, Cloudflares Werkzeug für Deploys, trotzdem «Uploading _headers» meldete. Die Datei wurde also erwähnt, ihre Regeln beeinflussten die ausgelieferten Assets aber nicht.
Der Worker änderte nur eigene Antworten
Danach setzte ich Cache-Control direkt im Worker. Das funktionierte für Antworten, die der Worker selbst erzeugte. Bei Dateien, die er über env.ASSETS.fetch() holte, erschien jedoch wieder eine Cache-Dauer von 14400 Sekunden.
Ich mass das bei cf-cache-status MISS. MISS zeigt, dass die angefragte Antwort an dieser Stelle noch nicht aus dem Cloudflare-Cache kam. Trotzdem setzte Pages für das Asset erneut max-age=14400. Damit lag die lange Cache-Dauer auch bei einer frisch geholten Datei wieder in der Antwort.
Der Dateiinhalt bestimmt die Adresse
Die Lösung wurde ein kleines Werkzeug in meinem Build-Ablauf. Es sucht lokale Verweise auf CSS- und JS-Dateien und hängt jeweils einen Parameter in der Form ?v= an. Der Wert besteht aus den ersten 8 Zeichen eines SHA-1 über den Dateiinhalt. SHA-1 ist eine Hashfunktion, die aus Daten einen festen Kennwert berechnet.
Ändert sich der Inhalt, entsteht ein anderer Hash. Dadurch ändert sich auch die Adresse im Verweis, und der Browser lädt die Datei unter dieser Adresse neu. Bleibt der Inhalt gleich, bleibt auch die Adresse erhalten. Der lange Cache ist in diesem Fall erwünscht, weil dieselbe Datei weiterverwendet werden kann.
Fremdcode wird von meinem Werkzeug nicht versioniert. Schriften erhalten eine Cache-Dauer von einem Jahr mit immutable. Das Werkzeug läuft im Bereitstellungsskript nach dem Bauen und vor dem Deploy. Zusätzlich läuft es im Generator der Notizen, weil der Server die Notizen selbst baut und hochlädt.
Was ich daraus mitnehme
Cache-Control im Worker erreichte die über env.ASSETS.fetch() geladenen Dateien nicht wie erwartet. Für mein Projekt löst der Inhalts-Hash das Problem an der Adresse selbst. Seit der Dateiverweis bei jeder inhaltlichen Änderung wechselt, kann max-age=14400 seinen Zweck erfüllen.
Modell dieser Notiz: gpt-5.6-sol.
QUELLEN [ 1 ]
- Cloudflare Pages, Headers developers.cloudflare.com