在執行階段中快取資源

網頁應用程式中的某些資產可能不常使用、非常大,或是會因使用者裝置 (例如回應式圖片) 或語言而有所不同。這些是預先快取可能為反模式的執行個體,您應改用執行階段快取功能。

在 Workbox 中,您可以使用 workbox-routing 模組處理資產的執行階段快取以比對路徑,並使用 workbox-strategies 模組處理資產的快取策略。

快取策略

您可使用其中一種內建的快取策略,處理大部分的資產路徑。這份說明文件先前有詳細說明,以下提供幾點重點回顧:

  • 「過時的舊作」會根據要求使用快取回應 (如果要求可用),並使用網路的回應更新背景快取。因此,如果資產未快取,就會等待網路回應並使用該資產。由於 SCC 會定期更新仰賴它的快取項目,因此這是非常安全的策略。缺點是一律在背景中向網路要求素材資源。
  • 網路優先會嘗試先從網路取得回應。如果收到回應,就會將回應傳遞至瀏覽器,並將其儲存至快取。如果網路要求失敗,系統會使用最後一個快取的回應,啟用該資產的離線存取功能。
  • 先快取會檢查回應的快取,接著再採用回應 (如果可用)。如果要求不在快取中,系統會使用網路,並將任何有效回應新增至快取,然後再傳送至瀏覽器。
  • 「僅限網路」會強制來自網路。
  • 「僅限快取」會強制要求來自快取的回應。

您可以使用 workbox-routing 提供的方法,套用這些策略來選取要求。

套用路徑比對的快取策略

workbox-routing 會公開 registerRoute 方法,以便比對路徑並透過快取策略處理這些路徑。registerRoute 接受 Route 物件,而這個物件又會接受兩個引數:

  1. 用來指定路線比對條件的字串、規則運算式比對回呼
  2. 路線的處理常式,通常是由 workbox-strategies 提供的策略。

建議比對回呼,因為它們提供的結構定義物件包含 Request 物件、要求網址字串、擷取事件,以及指出要求是否為相同來源要求的布林值。

處理常式會處理相符的路線。在以下範例中,系統會建立與傳入的相同來源圖片要求相符的新路徑,並先套用快取,再改回網路策略

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
  return sameOrigin && request.destination === 'image'
}, new CacheFirst());

// Register the new route
registerRoute(imageRoute);

使用多個快取

Workbox 可讓您使用套裝組合策略中的 cacheName 選項,將快取回應值區分至不同的 Cache 執行個體。

在以下範例中,圖片使用過時後的重新驗證策略,而 CSS 和 JavaScript 素材資源則使用快取優先改回網路策略。每個資產的路徑會新增 cacheName 屬性,將回應放入不同的快取。

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';

// Handle images:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image'
}, new StaleWhileRevalidate({
  cacheName: 'images'
}));

// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts'
}));

// Handle styles:
const stylesRoute = new Route(({ request }) => {
  return request.destination === 'style';
}, new CacheFirst({
  cacheName: 'styles'
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
Chrome 開發人員工具應用程式分頁中快取執行個體清單的螢幕截圖。顯示三個不同的快取:分別名為「scripts」,另一個名為「styles」,最後一個則是名為「images」的快取。
Chrome 開發人員工具「應用程式」面板中的快取儲存空間檢視器。系統會將不同資產類型的回應儲存在不同的快取中。

為快取項目設定到期日

管理 Service Worker 快取時須留意儲存空間配額。ExpirationPlugin 可簡化快取維護工作,並由 workbox-expiration 公開。如要使用,請在快取策略的設定中指定:

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'images',
  plugins: [
    new ExpirationPlugin({
      maxAgeSeconds: 60 * 60 * 24 * 30,
    })
  ]
}));

// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts',
  plugins: [
    new ExpirationPlugin({
      maxEntries: 50,
    })
  ]
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);

遵守儲存空間配額可能相當複雜。建議您考慮使用者可能遇到儲存壓力,或想要最有效運用儲存空間的使用者。Workbox 的ExpirationPlugin對夥伴可協助您達成這項目標。

跨來源注意事項

Service Worker 和跨來源資產之間的互動,遠與相同來源資產有極大差異。跨源資源共享 (CORS) 較為複雜,而複雜程度會擴及服務工作站中跨來源資源的處理方式。

不透明回應

no-cors 模式中提出跨來源要求時,回應可以儲存在 Service Worker 快取中,甚至供瀏覽器直接使用。不過,無法透過 JavaScript 讀取回應主體。這就是所謂的不透明回應

不透明回應是一種安全措施,用於防止檢查跨來源資產。您仍可提出跨來源資產要求,甚至快取這些資產,只是無法讀取回應內文,甚至無法讀取回應狀態碼

記得選擇啟用 CORS 模式

即使您載入的跨來源素材資源「確實」設定了許可 CORS 標頭讓您讀取回應,跨來源回應的內文可能仍不透明。舉例來說,下列 HTML 會觸發 no-cors 要求,無論設定哪些 CORS 標頭為何,都可能產生不透明的回應:

<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">

如要明確觸發會產生非不透明回應的 cors 要求,您必須在 HTML 中加入 crossorigin 屬性,明確選擇使用 CORS 模式:

<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">

當 Service Worker 中的路徑在執行階段中載入子資源時,請務必記住這個重點。

Workbox 可能無法快取不透明回應

根據預設,Workbox 會謹慎快取不透明回應。您無法檢查回應代碼是否有不透明的回應,因此如果使用優先快取或僅限快取的策略,快取錯誤回應可能會導致持續中斷的體驗。

如果需要在 Workbox 中快取不透明回應,您應使用「網路優先」或「過時即驗證」的策略來處理。是的,這表示網路每次仍會請求該素材資源,但這樣可確保失敗的回應不會保留,而且最終會替換為可用的回應。

如果您使用其他快取策略,且傳回不透明回應,Workbox 會警告,在開發模式下,並未快取回應。

強制快取不透明回應

如果您「絕對」想使用優先快取或僅限快取策略快取不透明回應,可以使用 workbox-cacheable-response 模組強制 Workbox 執行此操作:

import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

const cdnRoute = new Route(({url}) => {
  return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200]
    })
  ]
}))

registerRoute(cdnRoute);

不透明回應和 navigator.storage API

為避免跨網域資訊外洩,系統在計算儲存空間配額限制時,系統會為不透明回應大小加上明顯的邊框間距。這會影響 navigator.storage API 回報儲存空間配額的方式。

這個邊框間距會因瀏覽器而異,但在 Chrome 中,任何單一快取不透明回應的大小下限為約 7 MB 的儲存空間。當您決定要快取的不透明回應數量時,請留意這一點,因為這樣您就可以比預期更快地超出儲存空間配額。