請務必讓服務工作程式知道在要求部分回應時該如何處理。
部分 HTTP 要求包含 Range:
標頭,表示只應傳回完整資源的一部分。這類連結通常用於串流音訊或影片內容,可讓系統視需求載入較小的媒體片段,而非一次要求整個遠端檔案。
Service Worker 是位於網路應用程式和網路之間的 JavaScript 程式碼,可能會攔截傳出網路要求並產生回應。
以往,範圍要求和服務工作程之間的互動並不順暢。您必須採取特殊步驟,才能避免服務工作者產生不良結果。幸運的是,這種情況開始有所改變。在顯示正確行為的瀏覽器中,範圍要求會在經過服務工作者時「正常運作」。
問題說明
請考慮使用以下 fetch
事件監聽器的服務工作架構,該監聽器會接收每個傳入要求並將其傳遞至網路:
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
在行為不正確的瀏覽器中,如果 event.request
包含 Range:
標頭,則會在不發出通知的情況下捨棄該標頭。遠端伺服器收到的要求完全不會包含 Range:
。這並不會「破壞」任何內容,因為在原始要求中存在 Range:
標頭時,伺服器在技術上可以傳回完整的回應主體,並附上 200
狀態碼。但從瀏覽器的角度來看,這會導致傳輸的資料比實際所需的更多。
瞭解這項行為的開發人員可以透過明確檢查 Range:
標頭是否存在,並在存在時不呼叫 event.respondWith()
,來解決這個問題。如此一來,服務工作者就能有效地將自己從回應產生圖片中移除,並改用瞭解如何保留範圍要求的預設瀏覽器網路連線邏輯。
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));
});
不過,大部分開發人員都不知道需要這麼做。而且,我們也無法確認為何需要這項資訊。最終,這項限制是因為瀏覽器需要追上底層規格變更,而這項變更新增了對這項功能的支援。
修正內容
當 event.request
傳遞至 fetch()
時,正常運作的瀏覽器會保留 Range:
標頭。也就是說,如果瀏覽器設定了 Range:
標頭,我的初始範例中的服務工作站程式碼就會讓遠端伺服器看到該標頭:
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
伺服器現在可以正確處理範圍要求,並傳回部分回應和 206
狀態碼。
哪些瀏覽器的運作正常?
最新版本的 Safari 具有正確的功能。Chrome 和 Edge 87 以上版本也能正常運作。
截至 2020 年 10 月,Firefox 尚未修正這項行為,因此在將服務工作程式程式碼部署至正式版時,您可能仍需要考量這項行為。
如要確認特定瀏覽器是否已修正這項行為,最好的方法就是查看 Web 平台測試資訊主頁的「Include range header in network request」列。
從快取提供範圍要求的情況如何?
服務工作者不僅可將要求傳送至網路,還可執行更多操作。常見用途是將音訊和影片檔案等資源新增至本機快取。服務工作站就能從快取中滿足要求,完全略過網路。
所有瀏覽器 (包括 Firefox) 都支援在 fetch
處理常式中檢查要求,檢查是否有 Range:
標頭,然後使用快取中的 206
回應在本機上滿足要求。不過,服務工作程程式碼要正確剖析 Range:
標頭,並只傳回完整快取回應的適當部分,這並非易事。
幸好,需要協助的開發人員可以使用 Workbox,這是一組可簡化常見服務工作程用途的程式庫。workbox-range-request module
會實作直接從快取提供部分回應所需的所有邏輯。如需此用途的完整食譜,請參閱 Workbox 說明文件。
這篇文章的主頁橫幅圖片出自 Natalie Rhea Riggs 在 Unsplash 上的相片。