การแคชทรัพยากรระหว่างรันไทม์

เนื้อหาบางอย่างในเว็บแอปพลิเคชันอาจมีการใช้งานไม่บ่อย มีขนาดใหญ่มาก หรือแตกต่างกันไปตามอุปกรณ์ของผู้ใช้ (เช่น รูปภาพที่ตอบสนองตามอุปกรณ์) หรือภาษา กรณีเหล่านี้คือกรณีที่การแคชล่วงหน้าอาจเป็นรูปแบบที่เข้ากันไม่ได้ และคุณควรใช้การแคชรันไทม์แทน

ใน Workbox คุณสามารถจัดการการแคชรันไทม์สำหรับเนื้อหาโดยใช้โมดูล workbox-routing เพื่อจับคู่เส้นทาง และจัดการกลยุทธ์การแคชสำหรับเนื้อหาเหล่านั้นด้วยโมดูล workbox-strategies

กลยุทธ์การแคช

คุณสามารถจัดการเส้นทางส่วนใหญ่สำหรับเนื้อหาด้วยหนึ่งในกลยุทธ์การแคชในตัว ซึ่งกล่าวถึงรายละเอียดในเอกสารนี้ก่อนหน้านี้ แต่ยังมีประเด็นบางส่วนที่ควรพูดคุยกัน

  • ไม่มีอัปเดตขณะตรวจสอบอีกครั้งจะ��ช้การตอบกลับที่แคชไว้สำหรับคำขอ หากมี และอัปเดตแคชในเบื้องหลังด้วยการตอบกลับจากเครือข่าย ดังนั้นหากไม่มีการแคชเนื้อหา ระบบจะรอการตอบสนองของเครือข่ายและนำไปใช้ วิธีนี้เป็นกลยุทธ์ที่ค่อนข้างปลอดภัยเนื่องจากจะอัปเดตรายการแคชที่อาศัยกลยุทธ์ดังกล่าวเป็นประจำ ข้อเสียคือระบบจะขอชิ้นงานจากเครือข่ายในเบื้องหลังเสมอ
  • Network First จะพยายามรับการตอบสนองจากเครือข่ายก่อน หากได้รับการตอบกลับ ระบบจะส่งการตอบสนองนั้นไปยังเบราว์เซอร์และบันทึกลงในแคช หากขอเครือข่ายไม่สำเร็จ ระบบจะใช้การตอบสนองที่แคชไว้ล่าสุด ซึ่งเป็นการเปิดใช้การเข้าถึงเนื้อหาแบบออฟไลน์
  • แคชก่อนจะตรวจสอบแคชเพื่อดูการตอบกลับก่อนและใช้แคชดังกล่าวหากมี หากคำขอไม่ได้อยู่ในแคช ระบบจะใช้เครือข่ายและเพิ่มการตอบสนองที่ถูกต้องลงในแคชก่อนส่งไปยังเบราว์เซอร์
  • เครือข่ายเท่านั้น จะบังคับให้การตอบสนองมาจากเครือข่าย
  • แคชเท่านั้นจะบังคับให้การตอบกลับมาจากแคช

คุณสามารถใช้กลยุทธ์เหล่านี้เพื่อเลือกคำขอโดยใช้วิธีการของ workbox-routing

การใช้กลยุทธ์การแคชด้วยการจับคู่เส้นทาง

workbox-routing แสดงเมธอด registerRoute เพื่อจับคู่เส้นทางและจัดการเส้นทางด้วยกลยุทธ์การแคช registerRoute ยอมรับออบเจ็กต์ Route ซึ่งในทางกลับกันก็ยอมรับอาร์กิวเมนต์ 2 รายการ

  1. สตริง นิพจน์ทั่วไป หรือCallback ที่ตรงกันเพื่อระบุเกณฑ์การจับคู่เส้นทาง
  2. ตัวแฮนเดิลสำหรับเส้นทาง ซึ่งมักเป็นกลยุทธ์ที่ workbox-strategies มีให้

ควรใช้ Callback ที่ตรงกันเพื่อจับคู่เส้นทาง เนื่องจากมีออบเจ็กต์บริบทที่มีออบเจ็กต์ Request, สตริง URL ค��ขอ, เหตุการณ์การดึงข้อมูล และบ��ลี�����ี่��ะบุ�����า��ำขอเป็นคำขอต้นทางเดียวกันหรือไม่

จากนั้นตัวจัดการจะจัดการเส้นทางที่ตรงกัน ในตัวอย่างต่อไปนี้ ระบบจะสร้างเส้นทางใหม่ที่ตรงกับคำขอรูปภาพต้นทางเดียวกันที่กำลังจะเกิดขึ้น โดยใช้แคชก่อนและกลับไปใช้กลยุทธ์เครือข่าย

// 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 ช่วยให้คุณจัดเก็บคำตอบที่แคชไว้ไว้ในอินสแตนซ์ Cache แยกกันโดยใช้ตัวเลือก cacheName ที่มีอยู่ในกลยุทธ์แบบกลุ่ม

ในตัวอย่างต่อไปนี้ รูปภาพใช้กลยุทธ์ที่เก่าเกินไปขณะตรวจสอบความถูกต้องอีกครั้ง ขณะที่เนื้อหา 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);
ภาพหน้าจอของรายการอินสแตนซ์ Cache ในแท็บแอปพลิเคชันของเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome มีแคชแสดงอยู่ 3 รายการ ได้แก่ แคชรายการหนึ่งชื่อ "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);

การปฏิบัติตามโควต้าพื้นที่เก็บข้อมูลอาจเป็นเรื่องซับซ้อน แนวทางปฏิบัติที่ดีคือพิจารณาผู้ใช้ที่อาจประสบปัญหาพื้นที่เก็บข้อมูล หรือต้องการใช้พื้นที่เก็บข้อมูลให้คุ้มค่าที่สุด คู่ ExpirationPlugin ของ Workbox จะช่วยให้บรรลุเป้าหมายได้

ข้อควรพิจารณาข้ามแหล่งที่มา

การโต้ตอบระหว่าง Service Worker กับเนื้อหาแบบข้ามต้นทางมีความแตกต่างจากเนื้อหาต้นทางเดียวกันอย่างมาก Cross-Origin Resource Share (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 อย่างชัดแจ้งซึ่งจะแสดงการตอบกลับที่ไม่คลุมเครือ คุณต้องเลือกใช้โหมด CORS อย่างชัดแจ้งโดยเพิ่มแอตทริบิวต์ crossorigin ลงใน HTML ดังนี้

<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-cacheable-response โดยทำดังนี้

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 เมกะไบต์ คุณควรคำนึงถึงเรื่องนี้เมื่อพิจารณาจำนวนการตอบกลับแบบทึบที่ต้องการแคช เนื่องจากอาจทำให้เกินโควต้าพื้นที่เก็บข้อมูลได้เร็วกว่าที่คาดไว้มาก