Ressourcen während der Laufzeit zwischenspeichern

Einige Assets in Ihrer Webanwendung werden möglicherweise selten verwendet, sehr groß oder variieren je nach Gerät des Nutzers (z. B. responsive Bilder) oder Sprache. In diesen Fällen kann das Precaching ein Anti-Muster sein. In diesem Fall sollten Sie sich stattdessen auf das Laufzeit-Caching verlassen.

In Workbox können Sie das Laufzeit-Caching für Assets mit dem Modul workbox-routing für den Abgleich von Routen übernehmen und Caching-Strategien für sie mit dem Modul workbox-strategies.

Caching-Strategien

Sie können die meisten Routen für Assets mit einer der integrierten Caching-Strategien verarbeiten. Sie werden weiter oben in dieser Dokumentation ausführlich behandelt, aber hier sind einige noch einmal zusammengefasst:

  • Bei der erneuten Überprüfung veraltet verwendet eine im Cache gespeicherte Antwort für eine Anfrage, sofern diese verfügbar ist, und aktualisiert den Cache im Hintergrund mit einer Antwort des Netzwerks. Wenn das Asset nicht im Cache gespeichert ist, wird daher auf die Netzwerkantwort gewartet und dieses verwendet. Dies ist eine ziemlich sichere Strategie, da Cache-Einträge, die darauf angewiesen sind, regelmäßig aktualisiert werden. Der Nachteil ist, dass immer im Hintergrund ein Asset vom Netzwerk angefordert wird.
  • Network First versucht zuerst, eine Antwort vom Netzwerk zu erhalten. Wenn eine Antwort eingeht, wird sie an den Browser weitergeleitet und in einem Cache gespeichert. Schlägt die Netzwerkanfrage fehl, wird die letzte im Cache gespeicherte Antwort verwendet, wodurch der Offlinezugriff auf das Asset ermöglicht wird.
  • Cache First prüft zuerst den Cache auf eine Antwort und verwendet diese, falls verfügbar. Wenn sich die Anfrage nicht im Cache befindet, wird das Netzwerk verwendet und alle gültigen Antworten werden dem Cache hinzugefügt, bevor sie an den Browser übergeben werden.
  • Mit der Einstellung Nur Netzwerk wird erzwungen, dass die Antwort aus dem Netzwerk kommt.
  • Mit der Option Nur Cache wird erzwungen, dass die Antwort aus dem Cache stammt.

Sie können diese Strategien mit den von workbox-routing angebotenen Methoden auf Anfragen anwenden.

Caching-Strategien mit Routenabgleich anwenden

workbox-routing stellt eine registerRoute-Methode zum Abgleich von Routen bereit und verarbeitet sie mit einer Caching-Strategie. registerRoute akzeptiert ein Route-Objekt, das wiederum zwei Argumente akzeptiert:

  1. Ein String, ein regulärer Ausdruck oder ein Übereinstimmungs-Callback zum Angeben von Kriterien für den Routenabgleich.
  2. Ein Handler für die Route – normalerweise eine von workbox-strategies bereitgestellte Strategie.

Übereinstimmungs-Callbacks werden bevorzugt, um Routen abzugleichen, da sie ein Kontextobjekt bereitstellen, das das Request-Objekt, den Anfrage-URL-String, das Abrufereignis und einen booleschen Wert enthält, der angibt, ob die Anfrage eine Anfrage desselben Ursprungs ist.

Der Handler verarbeitet dann die übereinstimmende Route. Im folgenden Beispiel wird eine neue Route erstellt, die den eingehenden Bildanfragen desselben Ursprungs entspricht, wobei zuerst der Cache angewendet wird, wobei auf die Netzwerkstrategie zurückgegriffen wird.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
  return sameOrigin && request.destination === 'image'
}, new CacheFirst());

// Register the new route
registerRoute(imageRoute);

Mehrere Caches verwenden

Mit Workbox können Sie im Cache gespeicherte Antworten mithilfe der Option cacheName, die in den gebündelten Strategien verfügbar ist, in separate Cache-Instanzen gruppieren.

Im folgenden Beispiel wird für Bilder eine veraltete Strategie zur erneuten Validierung verwendet, während bei CSS- und JavaScript-Assets eine Cache-First-Methode angewendet wird, die auf eine Netzwerkstrategie zurückgreift. Die Route für jedes Asset platziert Antworten in separaten Caches, indem das Attribut cacheName hinzugefügt wird.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';

// Handle images:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image'
}, new StaleWhileRevalidate({
  cacheName: 'images'
}));

// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts'
}));

// Handle styles:
const stylesRoute = new Route(({ request }) => {
  return request.destination === 'style';
}, new CacheFirst({
  cacheName: 'styles'
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
Screenshot einer Liste von Cache-Instanzen auf dem Tab „Anwendung“ der Entwicklertools von Chrome Es sind drei verschiedene Caches zu sehen: einer mit dem Namen „scripts“, ein weiterer mit dem Namen „styles“ und der letzte mit dem Namen „images“.
Die Ansicht „Cache-Speicher“ im Bereich „Anwendung“ der Chrome-Entwicklertools. Antworten für verschiedene Asset-Typen werden in separaten Caches gespeichert.

Ablauf für Cache-Einträge festlegen

Achten Sie bei der Verwaltung von Service Worker-Caches auf Speicherkontingente. ExpirationPlugin vereinfacht die Cache-Wartung und wird durch workbox-expiration verfügbar gemacht. Geben Sie ihn in der Konfiguration für eine Caching-Strategie an, um ihn zu verwenden:

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'images',
  plugins: [
    new ExpirationPlugin({
      maxAgeSeconds: 60 * 60 * 24 * 30,
    })
  ]
}));

// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts',
  plugins: [
    new ExpirationPlugin({
      maxEntries: 50,
    })
  ]
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);

Die Einhaltung von Speicherkontingenten kann kompliziert sein. Es wird empfohlen, Nutzer zu berücksichtigen, die möglicherweise unter freier Speicherauslastung stehen oder ihren Speicher so effizient wie möglich nutzen möchten. Die ExpirationPlugin-Paare von Workbox können dabei helfen, dieses Ziel zu erreichen.

Ursprungsübergreifende Überlegungen

Die Interaktion zwischen Ihren Service Workern und ursprungsübergreifenden Assets unterscheidet sich erheblich von denen mit Same-Origin-Assets. Cross-Origin Resource Sharing (CORS) ist kompliziert und erstreckt sich auch auf die Handhabung von ursprungsübergreifenden Ressourcen in einem Service Worker.

Intransparente Antworten

Wenn eine ursprungsübergreifende Anfrage im no-cors-Modus gestellt wird, kann die Antwort in einem Service Worker-Cache gespeichert und sogar direkt vom Browser verwendet werden. Der Antworttext selbst kann jedoch nicht über JavaScript gelesen werden. Dies wird als opake Antwort bezeichnet.

Intransparente Antworten sind eine Sicherheitsmaßnahme, die die Prüfung eines ursprungsübergreifenden Assets verhindern soll. Du kannst weiterhin ursprungsübergreifende Assets anfordern und sogar im Cache speichern. Du kannst aber nicht den Antworttext lesen oder auch nicht den Statuscode lesen.

Denken Sie daran, den CORS-Modus zu aktivieren.

Selbst wenn Sie ursprungsübergreifende Assets laden, für die moderate CORS-Header festgelegt sind, die das Lesen von Antworten ermöglichen, ist der Text der ursprungsübergreifenden Antwort möglicherweise trotzdem intransparent. Der folgende HTML-Code löst beispielsweise no-cors-Anfragen aus, die unabhängig davon, welche CORS-Header festgelegt sind, zu intransparenten Antworten führen:

<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">

Wenn Sie explizit eine cors-Anfrage auslösen möchten, die eine intransparente Antwort liefert, müssen Sie den CORS-Modus explizit aktivieren. Fügen Sie dazu das Attribut crossorigin in den HTML-Code ein:

<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">

Das sollten Sie bedenken, wenn Routen in den Unterressourcen Ihres Service Worker-Cache zur Laufzeit geladen werden.

In der Arbeitsbox können intransparente Antworten nicht im Cache gespeichert werden.

Workbox geht beim Speichern intransparenter Antworten standardmäßig vorsichtig vor. Da es unmöglich ist, den Antwortcode auf intransparente Antworten zu prüfen, kann das Caching einer Fehlerantwort dazu führen, dass der Vorgang dauerhaft unterbrochen wird, wenn eine Cache-First- oder Nur-Cache-Strategie verwendet wird.

Wenn Sie eine intransparente Antwort in Workbox im Cache speichern müssen, sollten Sie dafür eine Strategie für das Netzwerk zuerst oder veraltete Validierung verwenden. Ja, das bedeutet, dass das Asset weiterhin jedes Mal vom Netzwerk angefordert wird. Es wird aber sichergestellt, dass fehlgeschlagene Antworten nicht bestehen bleiben und schließlich durch nutzbare Antworten ersetzt werden.

Wenn Sie eine andere Caching-Strategie verwenden und eine intransparente Antwort zurückgegeben wird, warnt Workbox Sie, dass die Antwort im Entwicklungsmodus nicht im Cache gespeichert wurde.

Caching von intransparenten Antworten erzwingen

Wenn Sie absolut sicher sind, dass Sie eine intransparente Antwort mit einer Cache-First- oder Nur-Cache-Strategie im Cache speichern möchten, können Sie Workbox mit dem workbox-cacheable-response-Modul dazu zwingen, dies zu tun:

import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

const cdnRoute = new Route(({url}) => {
  return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200]
    })
  ]
}))

registerRoute(cdnRoute);

Intransparente Antworten und die navigator.storage API

Um den Verlust von domainübergreifenden Informationen zu vermeiden, wird die Größe einer intransparenten Antwort, die bei der Berechnung von Speicherkontingentlimits verwendet wird, erheblich erhöht. Dies wirkt sich darauf aus, wie die navigator.storage API Speicherkontingente meldet.

Dieser Abstand variiert je nach Browser, aber für Chrome beträgt die Mindestgröße, die eine intransparente Antwort im Cache ungefähr 7 MB zum insgesamt genutzten Speicherplatz beiträgt. Dies sollten Sie berücksichtigen, wenn Sie festlegen, wie viele opake Antworten Sie im Cache speichern möchten, da Speicherkontingente schnell viel früher überschritten werden können als sonst.