Ga naar inhoud
HexaTransfer
Terug naar blog
Technische verdiepingen

Service Worker caching voor offline bestandsoverdracht

Gebruik Service Workers om offline bestandsoverdracht mogelijk te maken. Cachingstrategieen, achtergrondsynchronisatie en progressive web app-patronen.

Het NCSC benadrukt in zijn richtlijnen voor veilige applicaties dat veerkracht bij netwerkuitval onderdeel is van een goede beveiligingsstrategie — een half-voltooide bestandsoverdracht die gevoelige data achterlaat in een onzekere tussenstaat is een risico. Service Workers lossen dit op aan de basis: cache de HTML-shell en JavaScript met de Cache API, wachtrij mislukte uploads met de Background Sync API, sla gedeeltelijke stukken op in IndexedDB en herstel alles automatisch wanneer de verbinding terugkeert. De worker draait op een aparte thread met zijn eigen event loop, onderschept fetch-events voor zijn scope en blijft bestaan na het sluiten van tabbladen. De juiste aanpak: stale-while-revalidate voor de app-shell, IndexedDB-gebaseerde stukwachtrij voor lopende overdrachten, en een periodieke Background Sync-registratie die uploads elke vijftien minuten opnieuw probeert totdat ze slagen.

Wat Service Workers werkelijk doen voor overdrachtsapps

Het grote voordeel is dat navigator.serviceWorker tabbladherladen, offline perioden en zelfs telefoonslaapmodus overleeft. Wanneer een gebruiker een upload van 2 GB start op een instabiel trein-wifi, wilt u dat stukken die al zijn geslaagd geslaagd blijven, dat stukken die in de lucht zijn opnieuw worden geprobeerd bij herverbinding, en dat de gehele status herstelbaar is als de browser het tabblad sluit om geheugen vrij te maken. Een Service Worker — die onafhankelijk van een specifiek tabblad draait — is het onderdeel dat dit alles mogelijk maakt.

De API biedt u drie bouwstenen: Cache voor het opslaan van antwoorden per URL, IndexedDB voor gestructureerde data (stukwachtrijen, sessiestatus), en SyncManager voor het plannen van herhalingen die worden uitgevoerd wanneer het apparaat online is.

De worker registreren en versie-beheren

Registreer eenmalig bij het laden van de app en behandel updates expliciet:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js', { scope: '/' })
    .then((reg) => reg.addEventListener('updatefound', () => {
      const sw = reg.installing;
      sw.addEventListener('statechange', () => {
        if (sw.state === 'installed' && navigator.serviceWorker.controller) {
          // nieuwe versie gereed, gebruiker vragen te vernieuwen
        }
      });
    }));
}

Versie uw cachesleutels (transfer-v7) zodat een nieuwe deploy verouderde assets ongeldig maakt zonder verouderd JavaScript achter te laten. De klassieke bug: index.html wordt voor altijd gecacht, gebruikers krijgen de update nooit en u debugt weken via Slack. Koppel caches aan build-hashes en ruim op in het activate-event.

Cachingstrategieën voor app-shell versus gebruikersdata

Verschillende resources verdienen verschillende strategieën:

  • App-shell (HTML, CSS, JS, pictogrammen): cache-first met een terugval op het netwerk. Directe laadtijden, werkt offline.
  • API-metadata (/shares/:id): network-first met een cache-terugval, TTL van 60 seconden. Actueel wanneer online, bruikbaar wanneer niet.
  • Bestandsbytes: nooit cachen. Bestanden zijn vaak meerdere gigabytes en de Cache API heeft origineaquota's (doorgaans 60% van vrije schijfruimte).
  • Lettertypen van CDN's: stale-while-revalidate. Snel en automatisch bijgewerkt.

In de fetch-handler:

self.addEventListener('fetch', (e) => {
  const url = new URL(e.request.url);
  if (url.pathname.startsWith('/assets/')) {
    e.respondWith(cacheFirst(e.request, 'shell-v7'));
  } else if (url.pathname.startsWith('/api/shares/')) {
    e.respondWith(networkFirst(e.request, 'api-v1', 60));
  }
});

Onderschep nooit verzoeken voor binaire bestandsuploads — routeer eromheen door e.request.method === 'PUT' te controleren en vroeg terug te keren. PUT's van een gigabyte proxyen via de worker is een geheugencatastrofe.

Mislukte uploads in de wachtrij zetten met Background Sync

SyncManager is de sleutel tot veerkrachtige uploads. Wanneer een stuk-PUT mislukt, slaat u het op in IndexedDB en registreert u een sync:

// in paginacode
const reg = await navigator.serviceWorker.ready;
await reg.sync.register('flush-uploads');
// in sw.js
self.addEventListener('sync', (event) => {
  if (event.tag === 'flush-uploads') {
    event.waitUntil(flushPendingUploads());
  }
});

De browser vuurt het sync-event zodra het netwerk terugkeert, met exponentiële terugval tot circa 24 uur. Chrome en Edge ondersteunen dit; Safari leverde een subset in 17.5 onder de "Background Fetch"-vlag maar vereist gebruikersmachtiging. Voor Safari valt u terug op herproberen bij de volgende zichtbare paginaopening via visibilitychange.

De Background Fetch API is een apart gereedschap specifiek voor grote bestandsoperaties — het toont een blijvende melding in de browserinterface zodat gebruikers de voortgang kunnen volgen zelfs na het sluiten van het tabblad. Het waard om te gebruiken voor uploads boven 500 MB.

Gedeeltelijke uploads opslaan in IndexedDB

IndexedDB is uw duurzame kladruimte. Open een kleine database eenmalig en sla sessiemetadata plus stukoffsets op:

const db = await openDB('transfers', 1, {
  upgrade(db) {
    db.createObjectStore('sessions', { keyPath: 'id' });
    db.createObjectStore('chunks', { keyPath: ['sessionId', 'index'] });
  }
});
await db.put('sessions', {
  id, fileName, fileSize, fileFingerprint, createdAt: Date.now(),
  completedIndexes: [], partUrls
});

Sla geen ruwe stukbytes op — die komen van het File-handle, dat IndexedDB als een structured-clone-referentie kan bewaren die geldig blijft na herladen. Het handle bewaren vermijdt het dupliceren van 2 GB bytes in de database.

Originesopslag heeft limieten: ruwweg 60% van vrije schijfruimte op desktop Chrome, 1 GB per origine op iOS Safari voor evictiedruk optreedt. Vraag navigator.storage.persist() aan om de "persisted"-bucket te verkrijgen die browsers niet automatisch evicteren.

Online- en offline-overgangen afhandelen

Luister op online- en offline-events, zowel in de pagina als de service worker:

// pagina
window.addEventListener('online', () => {
  ui.showBanner('Weer online — uploads worden hervat');
  navigator.serviceWorker.controller?.postMessage({ type: 'resume' });
});
window.addEventListener('offline', () => {
  ui.showBanner('Offline — uploads gepauzeerd');
});

navigator.onLine is berucht onbetrouwbaar op zakelijke captive portals — het rapporteert true wanneer het apparaat een lokale netwerkverbinding heeft maar geen internet. Voor betrouwbare detectie voert u een klein fetch('/ping', { cache: 'no-store' }) uit met een time-out van drie seconden.

Er een echte PWA van maken

Lever een manifest.json met display: standalone, een pictogrammenset en start_url: /. Voeg apple-touch-icon-links toe voor iOS. Declareer bestandsafhandeling zodat het besturingssysteem uw app kan koppelen aan specifieke extensies:

{
  "name": "Hex Transfer",
  "file_handlers": [{
    "action": "/share-target",
    "accept": { "application/*": [".pdf", ".zip", ".docx"] }
  }]
}

Gecombineerd met Web Share Target laat dit gebruikers bestanden rechtstreeks vanuit het deelblad van het besturingssysteem in uw app zetten. Op Chrome Android en desktop Chromium kan de PWA zich registreren als standaardhandler voor de bestandstypen die u declareert. Dit verandert een browserpagina in een app die zich gedraagt als een native uploadtool.

Het offline-scenario testen

Drie scenario's om handmatig te testen, want geautomatiseerde offline-tests zijn onbetrouwbaar:

  1. Start een upload van 500 MB op snel wifi, schakel op 30% naar vliegtuigmodus, wacht 30 seconden, zet wifi terug aan. De upload moet hervatten zonder gebruikersactie.
  2. Start een upload, sluit het tabblad op 60%, wacht twee minuten, open opnieuw. Bied aan de sessie te hervatten.
  3. Start een upload op mobiel, vergrendel het scherm gedurende vijf minuten. Background Sync moet bij ontgrendeling worden uitgevoerd en de overdracht voltooien.

Chrome DevTools' "Offline"-selectievakje en Toepassing > Service Workers > Update bij herladen zijn onmisbaar. De "Throttling"-profielen in het Netwerk-paneel laten u Fast 3G en Slow 3G simuleren om te zien hoe uw fout-UI zich gedraagt.

HexaTransfer's webapp gebruikt een Service Worker voor app-shell-caching en IndexedDB voor lopende sessiestatus, zodat herladen en korte offline perioden geen uploadvoortgang verliezen. Probeer het op https://hexatransfer.com — gratis, geen account vereist, maximaal 10 GB.

Valkuilen die de moeite waard zijn te kennen

Service Workers hebben een kleine stapel voorbehouden die nieuwelingen verrassen: ze werken alleen over HTTPS (behalve localhost), cachequota's variëren sterk per browser, iOS Safari wekt workers niet betrouwbaar op voor Background Sync, DevTools kan verouderde workers agressief cachen (klik altijd op "Netwerk omzeilen" tijdens ontwikkeling), en importScripts loopt synchroon tijdens installatie, dus haal nooit trage scripts van derden op. Schrijf een kleine integratietest die controleert of de worker activeert, clients claimt en de offline-pagina serveert — die ene test vangt 80% van de regressies op die u in productie zult tegenkomen.

Verstuur grote bestanden veilig met end-to-end-versleuteling

Draag bestanden tot 10 GB gratis over met end-to-end-versleuteling. Geen account nodig. Uw bestanden worden in uw browser versleuteld voordat ze worden geüpload — niemand anders kan ze lezen.

Een bestand verzenden