在執行階段中快取資源

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

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

快取策略

您可以利用其中一種內建的快取策略來處理大部分的資產路徑。雖然我們提早在說明文件中詳細說明這些做法,但還是值得回顧:

  • WvalidateI 會將快取回應用於要求 (如果有的話),並透過網路回應更新背景的快取。因此,如果系統未快取資產,則會等待網路回應並使用該資產。因為這項策略會定期更新依賴該策略的快取項目,因此是相當安全的策略。但缺點是一律在背景向網路要求素材資源。
  • Network First 會先嘗試從網路取得回應。如果系統收到回應,就會將該回應傳送至瀏覽器,並將其儲存至快取。如果網路要求失敗,系統會使用最後一個快取的回應,啟用資產的離線存取功能。
  • 「先快取」會先檢查快取,並在可用的情況下使用回應。如果要求不在快取中,則會使用網路,並在傳送至瀏覽器之前,將所有有效的回應加入快取。
  • Network Only 可強制要求回應來自網路。
  • 僅快取可強制要求來自快取。

您可以使用 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) 很複雜,這種複雜性牽涉到在 Service Worker 中處理跨源資源的方式。

不透明回應

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。決定您要快取的不透明回應數量時,請務必記住這一點,因為您可能會比預期更快超過儲存空間配額。