การแสดงเสียงและวิดีโอที่แคช

วิธีที่เบราว์เซอร์บางประเภทจัดการคำขอเนื้อหาสื่อนั้นก็มีจุดอ่อน กล่าวคือ URL ที่ระบุในแอตทริบิวต์ src ขององค์ประกอบ <video> และ <audio> ซึ่งอาจทำให้เกิดลักษณะการแสดงผลที่ไม่ถูกต้อง เว้นแต่คุณจะทำตามขั้นตอนบางอย่างเมื่อกำหนดค่า Workbox

ปัญหา

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

  • ต้องบอกให้ช่องงานทำตามส่วนหัวของคำขอ Range โดยใช้โมดูล workbox-range-requests กับกลยุทธ์ที่ใช้เป็นตัวแฮนเดิล
  • องค์ประกอบ <video> หรือ <audio> ต้องเลือกใช้โหมด CORS ที่มีแอตทริบิวต์ crossorigin
  • หากต้องการแสดงสื่อจากแคช คุณควรเพิ่มสื่อนั้นไว้ในแคชอย่างชัดเจนล่วงหน้า ซึ่งทำได้โดยการแคชล่วงหน้าหรือด้วย cache.add() หรือโดยใช้เมธอด WarmStrategyCache ในสูตรของเวิร์กบ็อกซ์ การแคชเนื้อหาสื่อขณะสตรีมขณะรันไทม์จะไม่ทำงาน เนื่องจากระบบจะดึงเนื้อหาเพียงบางส่วนจากเครือข่ายในระหว่างการเล่น

วิธีปฏิบัติตามข้อกำหนดเหล่านี้ใน Workbox โดยเริ่มต้นจากมาร์กอัปที่เหมาะสมสำหรับเนื้อหาสื่อ

<!-- In your page: -->

<!-- You need to set `crossorigin`, even for same-origin URLs! -->
<video src="movie.mp4" crossorigin="anonymous"></video>
<audio src="song.mp3" crossorigin="anonymous"></audio>

จากนั้นใน Service Worker ให้ใช้ปลั๊กอิน workbox-range-request เพื่อจัดการเนื้อหาสื่อดังนี้

// sw.js
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
import {RangeRequestsPlugin} from 'workbox-range-requests';

// In your service worker:
// It's up to you to either precache, use warmRuntimeCache, or
// explicitly call cache.add() to populate the cache with media assets.
// If you choose to cache media assets up front, do so with care,
// as they can be quite large and exceed storage quotas.
//
// This route will go to the network if there isn't a cache match,
// but it won't populate the cache at runtime because the response for
// the media asset will be a partial 206 response. If there is a cache
// match, then it will properly serve partial responses.
registerRoute(
  ({request}) => {
    const {destination} = request;

    return destination === 'video' || destination === 'audio'
  },
  new CacheFirst({
    cacheName: 'your-cache-name-here',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [200]
      }),
      new RangeRequestsPlugin(),
    ],
  }),
);

วิธีนี้ทำให้มั่นใจได้ว่า Service Worker จะดึงและแคชเนื้อหาสื่อของเว็บไซต์อย่างถูกต้อง ขณะเดียวกันก็นำคำขอข้อมูลช่วงและข้อผิดพลาดอื่นๆ ที่อาจเกิดขึ้นเกี่ยวกับคำขอสื่อมาพิจารณาด้วย