Data di pubblicazione: 6 ottobre 2020
Alcune richieste HTTP contengono un'intestazione Range:, che indica che deve essere restituita solo una parte della risorsa completa. Vengono comunemente utilizzati per lo streaming di contenuti audio o video per consentire il caricamento on demand di blocchi più piccoli di contenuti multimediali, anziché richiedere l'intero file remoto in una sola volta.
Un service worker è un codice JavaScript che si trova tra l'app web e la rete, intercettando potenzialmente le richieste di rete in uscita e generando risposte.
In passato, le richieste di intervalli e i service worker non hanno funzionato bene insieme. È stato necessario adottare misure speciali per evitare risultati negativi nel service worker. Fortunatamente, la situazione sta iniziando a cambiare. Nei browser che mostrano il comportamento corretto, le richieste di intervallo "funzionano" quando passano attraverso un service worker.
Qual è il problema?
Considera un service worker con il seguente listener di eventi fetch, che prende 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 includeva un'intestazione Range:, questa veniva eliminata automaticamente. La richiesta ricevuta dal server remoto non includerà Range:. Ciò non "interrompe" necessariamente nulla, poiché a un server è tecnicamente consentito restituire l'intero corpo della risposta, con un codice di stato 200, anche quando è presente un'intestazione Range: nella richiesta originale. ma comporterebbe il trasferimento di più dati di quelli strettamente necessari dal punto di vista del browser.
Gli sviluppatori consapevoli di questo comportamento possono aggirarlo controllando esplicitamente la presenza di un'intestazione Range: e non chiamando event.respondWith() se è presente. In questo modo, il service worker si rimuove effettivamente dalla generazione di risposte e viene utilizzata la logica di rete predefinita del browser, che sa come conservare 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));
});
È sicuro affermare che la maggior parte degli sviluppatori non era consapevole della necessità di farlo. E non era chiaro perché dovesse essere obbligatorio. In definitiva, questa limitazione era dovuta al fatto che i browser dovevano recuperare il ritardo rispetto alle modifiche alla specifica sottostante, che hanno aggiunto il supporto per questa funzionalità.
Cosa è stato corretto?
I browser che si comportano correttamente conservano l'intestazione Range: quando event.request viene passato a fetch(). Ciò significa che il codice del service worker nel mio esempio iniziale consentirà al server remoto di visualizzare 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 ottobre 2020, Firefox non ha ancora corretto questo comportamento, quindi potresti doverlo tenere in considerazione durante il deployment del codice del service worker in produzione.
Selezionare la riga "Include range header in network request" (Includi intestazione intervallo nella richiesta di rete) della dashboard dei test della piattaforma web è il modo migliore per verificare se un determinato browser ha corretto questo comportamento.
Che dire della gestione delle richieste di intervallo dalla cache?
I service worker possono fare molto di più che semplicemente inoltrare una richiesta alla rete. Un caso d'uso comune è l'aggiunta di risorse, come file audio e video, a una cache locale. Un service worker può quindi soddisfare le richieste dalla cache, bypassando completamente la rete.
Tutti i browser, incluso Firefox, supportano l'ispezione di una richiesta all'interno di un gestore fetch, la verifica della presenza dell'intestazione Range: e quindi l'evasione locale della richiesta con una risposta 206 proveniente da una cache. 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 rivolgersi a Workbox, un insieme di librerie che semplificano i casi d'uso comuni dei service worker. workbox-range-request module implementa tutta la logica necessaria per pubblicare risposte parziali direttamente dalla cache. Una ricetta completa per questo caso d'uso è disponibile nella documentazione di Workbox.