Gestione delle richieste di intervalli in un service worker

Assicurati che il service worker sappia cosa fare quando viene richiesta una risposta parziale.

Alcune richieste HTTP contengono un'intestazione Range:, che indica che deve essere restituita solo una parte della risorsa completa. Sono comunemente utilizzati per lo streaming di contenuti audio o video al fine di consentire il caricamento on demand di frammenti più piccoli di contenuti multimediali, invece di richiedere l'intero file remoto in una volta sola.

Un service worker è un codice JavaScript che si trova tra l'applicazione web e la rete e che potenzialmente intercetta le richieste di rete in uscita e genera risposte.

In passato, le richieste di intervallo e i service worker non hanno funzionato bene insieme. È stato necessario adottare delle misure speciali per evitare problemi con il service worker. Fortunatamente, le cose stanno iniziando a cambiare. Nei browser con il comportamento corretto, le richieste di intervallo "funzionano" semplicemente quando passano attraverso un service worker.

Qual è il problema?

Prendi in considerazione un service worker con il seguente listener di eventi fetch, che accetta ogni richiesta in entrata e la passa alla rete:

self.addEventListener('fetch', (event) => {
  // The Range: header will not pass through in
  // browsers that behave incorrectly.
  event.respondWith(fetch(event.request));
});

Nei browser con il comportamento errato, se event.request includesse un'intestazione Range:, quest'ultima verrebbe eliminata automaticamente. La richiesta ricevuta dal server remoto non includeva affatto Range:. Ciò non "interrompe" necessariamente qualcosa, poiché un server è tecnicamente autorizzato a restituire il corpo completo della risposta, con un codice di stato 200, anche quando è presente un'intestazione Range: nella richiesta originale. Tuttavia, il trasferimento di una quantità di dati maggiore di quello strettamente necessario dal punto di vista del browser ne comporterebbe una maggiore quantità.

Gli sviluppatori che erano a conoscenza di questo comportamento potrebbero aggirare il problema controllando esplicitamente la presenza di un'intestazione Range: e non chiamando event.respondWith() se presente. In questo modo il service worker si rimuove in modo efficace dall'immagine di generazione delle risposte e viene utilizzata la logica di networking del browser predefinita, che sa come preservare le richieste di intervallo.

self.addEventListener('fetch', (event) => {
  // Return without calling event.respondWith()
  // if this is a range request.
  if (event.request.headers.has('range')) {
    return;
  }

  event.respondWith(fetch(event.request));
});

Possiamo affermare che la maggior parte degli sviluppatori non era a conoscenza di questa necessità. Inoltre, non era chiaro perché questo debba essere fatto. In definitiva, questa limitazione era dovuta al fatto che i browser dovevano mettersi al passo con le modifiche alla specifica sottostante, a cui è stato aggiunto il supporto di questa funzionalità.

Che cosa è stato corretto?

I browser che si comportano correttamente conservano l'intestazione Range: quando event.request viene trasmesso a fetch(). Questo significa che il codice del service worker nel mio esempio iniziale consentirà al server remoto di vedere l'intestazione Range:, se è stata impostata dal browser:

self.addEventListener('fetch', (event) => {
  // The Range: header will pass through in browsers
  // that behave correctly.
  event.respondWith(fetch(event.request));
});

Il server ora ha la possibilità di gestire correttamente la richiesta di intervallo e restituire una risposta parziale con un codice di stato 206.

Quali browser si comportano correttamente?

Le versioni recenti di Safari hanno la funzionalità corretta. Anche Chrome ed Edge, a partire dalla versione 87, si comportano correttamente.

A partire da ottobre 2020, Firefox non ha ancora corretto questo comportamento, perciò potresti doverlo ancora tenere conto durante il deployment del codice del service worker in produzione.

Selezionare la riga "Includi intestazione intervallo nella richiesta di rete" della dashboard Web Platform Test è il modo migliore per verificare se un determinato browser ha corretto questo comportamento.

E per quanto riguarda la gestione delle richieste di intervallo dalla cache?

I service worker possono fare molto di più che passare una richiesta alla rete. Un caso d'uso comune consiste nell'aggiungere risorse, ad esempio file audio e video, a una cache locale. Un service worker può quindi soddisfare le richieste da quella cache, bypassando completamente la rete.

Tutti i browser, incluso Firefox, supportano l'ispezione di una richiesta all'interno di un gestore fetch, il controllo della presenza dell'intestazione Range: e quindi l'esecuzione locale della richiesta con una risposta 206 che proviene da una cache. Tuttavia, il codice del service worker per analizzare correttamente l'intestazione Range: e restituire solo il segmento appropriato della risposta completa memorizzata nella cache non è banale.

Fortunatamente, gli sviluppatori che hanno bisogno di aiuto possono utilizzare Workbox, un insieme di librerie che semplifica i casi d'uso comuni dei service worker. L'elemento workbox-range-request module implementa tutta la logica necessaria per fornire risposte parziali direttamente dalla cache. Il modello completo per questo caso d'uso è disponibile nella documentazione di Workbox.

L'immagine hero in questo post è di Natalie Rhea Riggs su Unsplash.