處理 Service Worker 中的範圍要求

請務必讓服務工作程式知道在要求部分回應時該如何處理。

部分 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:。這不一定會造成任何「破壞」的情況,因為伺服器技術上可以傳回完整的回應主體 (含有 200 狀態碼),即使原始要求中有 Range: 標頭也一樣。但從瀏覽器的角度來看,這會導致傳輸的資料比實際所需的更多。

瞭解這項行為的開發人員可以透過明確檢查 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 Platform Tests 資訊主頁的「在網路要求中加入範圍標頭」資料列,是確認特定瀏覽器是否已修正這項行為的最佳方式。

那來自快取的提供範圍要求呢?

服務工作者不僅可將要求傳送至網路,還可執行更多操作。常見的用途是將音訊和影片檔案等資源新增至本機快取。服務工作站就能從快取中滿足要求,完全略過網路。

所有瀏覽器 (包括 Firefox) 都支援在 fetch 處理常式中檢查要求,檢查是否有 Range: 標頭,然後使用快取中的 206 回應在本機上滿足要求。不過,服務工作程程式碼要正確剖析 Range: 標頭,並只傳回完整快取回應的適當部分,這並非易事。

幸好,需要協助的開發人員可以使用 Workbox,這是一組可簡化常見服務工作程用途的程式庫。workbox-range-request module 會實作直接從快取提供部分回應所需的所有邏輯。如需此用途的完整食譜,請參閱 Workbox 說明文件

這篇文章的主頁橫幅圖片出自 Unsplash 上的 Natalie Rhea Riggs