Umgang mit dem Browser-Cache in einseitigen Apps

27

Ich versuche herauszufinden, wie der Webbrowser-Cache für Apps mit nur einer Seite richtig gehandhabt wird.

Ich habe ein ziemlich typisches Design: mehrere HTML-, JS- und CSS-Dateien, die das SPA implementieren, und eine Reihe von JSON-Daten, die vom SPA verwendet werden. Probleme treten auf, wenn ich ein Update pushen möchte: Ich aktualisiere den statischen Teil der Site und den Code, der JSON generiert, gleichzeitig, aber bei Client-Browsern wird der statische Teil häufig zwischengespeichert, sodass alter Code versucht, die neuen Daten zu verarbeiten und kann (abhängig von den vorgenommenen Änderungen) auf Probleme stoßen. (Insbesondere scheint der IE aggressiver zu sein als Chrome oder Firefox, wenn es darum geht, zwischengespeichertes JS ohne erneute Überprüfung zu verwenden.)

Wie geht man am besten damit um?

  1. Stellen Sie sicher, dass meine JSON-Änderungen abwärtskompatibel sind, und gehen Sie davon aus, dass die Browser-Caches in einem angemessenen Zeitraum ablaufen.
  2. Integrieren Sie eine Art Versionsnummer sowohl in das statische JS als auch in das JSON und führen window.location.reload(true);Sie sie aus , wenn sie nicht übereinstimmen.
  3. Ermitteln Sie die geeignete Kombination von Headern ( must-revalidateoder no-cachewas auch immer; Quellen variieren in Bezug auf die Vorgehensweise), um sicherzustellen, dass Browser bei jedem Ladevorgang immer alle Ressourcen erneut validieren, auch wenn dies einige zusätzliche Roundtrips zum Laden der Site bedeutet.
  4. Verwalte meine Cache-Kontrolle und lösche Header, so dass statische Inhalte verfallen, wenn ich ein Update veröffentlichen möchte.
  5. Etwas anderes?
Josh Kelley
quelle
1
Habe gehört, dass # 3 und # 4 unerwartet in eingebetteten Webbrowser-Steuerelementen versagen, wenn Ihre Umgebung von Kollegen schlecht ist ( Husten iOS). # 1 und # 2 können eine Wahl auf App-Ebene sein, können aber dennoch (?) Cache-Probleme für andere Ressourcen oder für teilweise Ressourcenlasten verursachen. Das einzige, was ich im produktionsbereiten Code zuverlässig gesehen habe, ist das Abrufen von yoururl.html? <SomeTimeStamp>, da hierdurch die meisten Caching-Mechanismen ausgeblendet werden. Bonus: Rollen Sie Ihre gesamte Web-App in eine Datei, sodass das Laden entweder atomar erfolgreich ist oder fehlschlägt. Nachteil: Funktioniert am besten auf einem lokalen Link. Ihr Kilometerstand kann variieren. Viel Glück!
J Trana
2
+1 für die Verwendung einer Versionsnummer oder eines Zeitstempels als URL-Parameter für Ressourcen.
9000,

Antworten:

14

Sie benötigen eine Cache-Busting- Lösung. Die Rolle des Cache-Bustings ist:

  1. Benennen Sie Ressourcen je nach Inhalt in einen eindeutigen Namen um.
  2. Aktualisieren Sie alle Verweise auf diese Ressourcen.

In einem Grunt-basierten Projekt wird häufig grunt-rev verwendet, um sicherzustellen, dass alle zu aktualisierenden Dateien je nach Inhalt eindeutige Namen erhalten.

Wenn Sie sicherstellen, dass Ihre JSON-Dateien Cachebusting-Dateinamen sowie die Verweise darauf in Ihrem Javascript erhalten, laden Clients immer die JSON-Dateien, die das Javascript erwartet.

Der Vorteil von Hash-basierten Dateinamen besteht darin, dass Dateien, die nicht geändert wurden, nach dem Cache-Busting dieselben Dateinamen erhalten, sodass Browser den zwischengespeicherten Inhalt auch dann sicher verwenden können, wenn er nicht geändert wurde.

Offensichtlich ist dies die Art von Dingen, die Sie als Teil der Produktionserstellung Ihres Projekts automatisieren möchten, damit Sie Änderungen an Dateinamen und Referenzen nicht manuell nachverfolgen müssen.

Ted Percival
quelle
2
+1 für das kursiv geschriebene "Cache Busting" -Bit, das die Tür öffnet, um dieses Zeug tatsächlich produktiv zu googeln.
Zak Kus
@ Ted Percival - Yeoman Framework macht das, was ich benutze, aber ich sehe ein Problem. Wenn ich ein neues Build veröffentliche, wird möglicherweise die index.html mit Verweisen auf die alten Dateien im Cache des Browsers gespeichert ... und der Browser erhält eine Fehlermeldung. Wie soll ich das beheben? (A.) Verknüpfen Sie alle alten Dateinamen mit den neuen (dies funktioniert) (B.) Fügen Sie der Datei index.html einen No-Cache-Header hinzu (dies wird jedoch immer beachtet). (C.) Fügen Sie .htaccess hinzu, um eine revidierte Datei zu erkennen und suche nach der Basis (dh 12345.main.js -> main.js)
timh
5

Sie können if-modified-since + last-modifiedoder -Header if-none-match + etagzusammen mit dem richtigen cache-controlHeader verwenden. (Es kann Browser-Fehler geben , aber nichts, was Sie in neueren Browsern nicht verwalten können.)

Wenn die Dateien statisch sind, empfehle ich die Verwendung if-modified-since, da dies automatisch mit einem gut konfigurierten HTTP-Server durchgeführt werden kann. Es sollte 304 zurücksenden, wenn die Datei seit dem letzten Download nicht geändert wurde.

Ich denke nicht, dass Ihre Nr. 1 und Nr. 2 langfristig funktionieren würden. Die Nr. 3 oder Nr. 4 können funktionieren. Die Nummer 3 ist einfacher, aber Sie müssen erst einmal lernen, mit diesem Problem umzugehen. Wenn ich Sie wäre, würde ich die Nummer 4 ausprobieren, aber die Lösung könnte davon abhängen, welche Browser Ihre Kunden verwenden ... IE8 hat beispielsweise Probleme beim Aktualisieren des Ajax-Caches usw.

inf3rno
quelle
2

Wenn Sie den Java-Servlet-Filter in Ihr SPA aufnehmen können, ist dies eine funktionierende Lösung: CorrectBrowserCacheHandlerFilter.java

Wenn Ihr Browser die statischen Dateien anfordert, leitet der Server grundsätzlich alle Anforderungen an dieselbe weiter, jedoch mit einem Hash-Abfrageparameter ( ?v=azErTzum Beispiel), der vom Inhalt der statischen Zieldatei abhängt.

Auf diese Weise speichert der Browser niemals die statischen Dateien zwischen, die in Ihrem index.htmlBeispiel deklariert sind (weil immer ein a empfangen wird 302 Moved Temporarily), sondern speichert nur die Dateien mit der Hash-Version zwischen (der Server antwortet darauf 200). Daher wird der Browser-Cache für statische Dateien mit einer Hash-Version effizient genutzt.

Haftungsausschluss: Ich bin der Autor von CorrectBrowserCacheHandlerFilter.java.

Anthony O.
quelle