Bronnen in cache opslaan tijdens runtime

Sommige middelen in uw webapplicatie worden mogelijk niet vaak gebruikt, zijn erg groot of variëren afhankelijk van het apparaat van de gebruiker (zoals responsieve afbeeldingen) of de taal. Dit zijn gevallen waarin precaching een anti-patroon kan zijn en u in plaats daarvan moet vertrouwen op runtime-caching.

In Workbox kunt u runtime-caching voor assets afhandelen met behulp van de workbox-routing module om routes af te stemmen, en caching-strategieën daarvoor afhandelen met de workbox-strategies module .

Caching-strategieën

U kunt de meeste routes voor assets afhandelen met een van de ingebouwde cachingstrategieën. Ze worden eerder in deze documentatie gedetailleerd besproken , maar hier zijn er een paar die de moeite waard zijn om samen te vatten:

  • Stale While Revalidate gebruikt een in de cache opgeslagen antwoord voor een verzoek als dit beschikbaar is en werkt de cache op de achtergrond bij met een antwoord van het netwerk. Als de asset niet in de cache is opgeslagen, wacht deze daarom op de reactie van het netwerk en gebruikt deze. Het is een redelijk veilige strategie, omdat het regelmatig cache-items bijwerkt die ervan afhankelijk zijn. Het nadeel is dat het altijd op de achtergrond een asset van het netwerk opvraagt.
  • Network First probeert eerst een reactie van het netwerk te krijgen. Als er een antwoord wordt ontvangen, wordt dat antwoord doorgegeven aan de browser en opgeslagen in een cache. Als het netwerkverzoek mislukt, wordt het laatste in de cache opgeslagen antwoord gebruikt, waardoor offline toegang tot de asset mogelijk wordt.
  • Cache First controleert eerst de cache op een antwoord en gebruikt dit indien beschikbaar. Als het verzoek niet in de cache staat, wordt het netwerk gebruikt en wordt elk geldig antwoord aan de cache toegevoegd voordat het aan de browser wordt doorgegeven.
  • Alleen Netwerk dwingt het antwoord van het netwerk te komen.
  • Alleen Cache dwingt het antwoord uit de cache te komen.

U kunt deze strategieën toepassen om aanvragen te selecteren met behulp van methoden die worden aangeboden door workbox-routing .

Cachingstrategieën toepassen met routematching

workbox-routing stelt een registerRoute methode beschikbaar om routes te matchen en deze af te handelen met een caching-strategie. registerRoute accepteert een Route object dat op zijn beurt twee argumenten accepteert:

  1. Een tekenreeks, reguliere expressie of een match-callback om route-matchingscriteria op te geven.
  2. Een handler voor de route, meestal een strategie die wordt geboden door workbox-strategies .

Match-callbacks hebben de voorkeur boven match-routes, omdat ze een contextobject bieden dat het Request object , de request-URL-tekenreeks, de fetch-gebeurtenis en een boolean bevat die aangeeft of het verzoek een verzoek van dezelfde oorsprong is.

De handler handelt vervolgens de overeenkomende route af. In het volgende voorbeeld wordt een nieuwe route gemaakt die overeenkomt met binnenkomende afbeeldingsverzoeken van dezelfde oorsprong, waarbij eerst de cache wordt toegepast en terugvalt op de netwerkstrategie .

// 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);

Meerdere caches gebruiken

Met Workbox kunt u in de cache opgeslagen antwoorden in afzonderlijke Cache instanties plaatsen met behulp van de cacheName optie die beschikbaar is in de gebundelde strategieën.

In het volgende voorbeeld gebruiken afbeeldingen een verouderde-terwijl-revalidate-strategie, terwijl CSS- en JavaScript-items een cache-first gebruiken die terugvalt op de netwerkstrategie. De route voor elke asset plaatst antwoorden in afzonderlijke caches, door de eigenschap cacheName toe te voegen.

// 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);
Een screenshot van een lijst met cache-instanties op het applicatietabblad van Chrome's DevTools. Er worden drie verschillende caches getoond: één met de naam 'scripts', een andere met de naam 'styles', en de laatste heet 'images'.
De cacheopslagviewer in het applicatiepaneel van Chrome DevTools. Antwoorden voor verschillende assettypen worden in afzonderlijke caches opgeslagen.

Een vervaldatum instellen voor cache-items

Houd rekening met opslagquota bij het beheren van cache(s) voor servicemedewerkers. ExpirationPlugin vereenvoudigt het cache-onderhoud en wordt zichtbaar door workbox-expiration . Om het te gebruiken, specificeert u het in de configuratie voor een cachingstrategie:

// 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);

Het voldoen aan opslagquota kan ingewikkeld zijn. Het is een goede gewoonte om rekening te houden met gebruikers die mogelijk opslagdruk ervaren of hun opslag zo efficiënt mogelijk willen gebruiken. ExpirationPlugin paren van Workbox kunnen helpen bij het bereiken van dat doel.

Cross-oorsprongoverwegingen

De interactie tussen uw servicemedewerker en cross-originele activa is aanzienlijk anders dan bij activa van dezelfde oorsprong. Cross-Origin Resource Sharing (CORS) is ingewikkeld, en die complexiteit strekt zich uit tot de manier waarop u omgaat met cross-origine bronnen in een servicemedewerker.

Ondoorzichtige reacties

Wanneer u een cross-origin-verzoek doet in no-cors modus , kan het antwoord worden opgeslagen in de cache van een servicemedewerker en zelfs rechtstreeks door de browser worden gebruikt. De antwoordtekst zelf kan echter niet via JavaScript worden gelezen. Dit staat bekend als een ondoorzichtige reactie .

Ondoorzichtige reacties zijn een beveiligingsmaatregel die bedoeld is om de inspectie van een cross-origin asset te voorkomen. U kunt nog steeds verzoeken indienen voor cross-origin assets en deze zelfs in de cache opslaan, u kunt alleen de antwoordtekst niet lezen of zelfs de statuscode ervan lezen!

Vergeet niet om u aan te melden voor de CORS-modus

Zelfs als u cross-origin-items laadt die wel toegestane CORS-headers instellen waarmee u reacties kunt lezen, kan de hoofdtekst van de cross-origin-reactie nog steeds ondoorzichtig zijn. De volgende HTML activeert bijvoorbeeld no-cors verzoeken die tot ondoorzichtige reacties leiden, ongeacht welke CORS-headers zijn ingesteld:

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

Om expliciet een cors verzoek te activeren dat een niet-ondoorzichtig antwoord oplevert, moet u zich expliciet aanmelden voor de CORS-modus door het crossorigin attribuut aan uw HTML toe te voegen:

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

Dit is belangrijk om te onthouden wanneer routes in de cache van uw service worker-subbronnen tijdens runtime worden geladen.

Workbox mag ondoorzichtige antwoorden niet in de cache opslaan

Standaard hanteert Workbox een voorzichtige benadering bij het cachen van ondoorzichtige reacties. Omdat het onmogelijk is om de responscode te onderzoeken op ondoorzichtige antwoorden, kan het in de cache opslaan van een foutreactie resulteren in een aanhoudend verstoorde ervaring als er een strategie voor eerst cache of alleen cache wordt gebruikt.

Als u een ondoorzichtig antwoord in Workbox in de cache moet opslaan, moet u een netwerk-eerst- of verouderde-terwijl-valideren-strategie gebruiken om dit af te handelen. Ja, dit betekent dat de asset nog steeds elke keer bij het netwerk wordt opgevraagd, maar het zorgt ervoor dat mislukte reacties niet blijven bestaan ​​en uiteindelijk worden vervangen door bruikbare reacties.

Als u een andere cachingstrategie gebruikt en er een ondoorzichtig antwoord wordt geretourneerd, waarschuwt Workbox u dat het antwoord niet in de cache is opgeslagen in de ontwikkelingsmodus .

Forceer caching van ondoorzichtige reacties

Als u er absoluut zeker van bent dat u een ondoorzichtig antwoord in de cache wilt opslaan met behulp van een cache-first- of cache-only-strategie, kunt u Workbox dwingen dit te doen met de workbox-cacheable-response module :

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);

Ondoorzichtige reacties en de navigator.storage API

Om het lekken van informatie over meerdere domeinen te voorkomen, is er aanzienlijke opvulling toegevoegd aan de grootte van een ondoorzichtig antwoord dat wordt gebruikt voor het berekenen van opslagquotumlimieten. Dit heeft invloed op de manier waarop de navigator.storage API opslagquota rapporteert.

Deze opvulling verschilt per browser, maar voor Chrome is de minimale grootte die een enkele in de cache opgeslagen ondoorzichtige reactie bijdraagt ​​aan de totale gebruikte opslagruimte ongeveer 7 megabytes . U moet hier rekening mee houden wanneer u bepaalt hoeveel ondoorzichtige reacties u in de cache wilt opslaan, omdat u de opslagquota gemakkelijk veel eerder kunt overschrijden dan u anders zou verwachten.