传送缓存的音频和视频

某些浏览器在处理媒体素材资源请求(即在 <video><audio> 元素的 src 属性中指定的网址)方面存在一些细微差别,除非您在配置 Workbox 时采取特定步骤,否则可能会导致错误的投放行为。

问题

如需详细了解浏览器在传送音频和视频资源方面所遇到的复杂问题,请参阅这篇 GitHub 问题讨论。整个过程非常复杂,但要点如下:

  • 对用作处理程序的策略使用 workbox-range-requests 模块,告知 Workbox 遵从 Range 请求标头
  • <video><audio> 元素需要使用 crossorigin 属性选择启用 CORS 模式。
  • 如果您想从缓存传送媒体,则应提前将其明确添加到缓存。您可以通过预缓存或使用 cache.add() 或者在 workbox-recipes 中使用 hotStrategyCache 方法来实现这一点。无法在运行时缓存媒体素材资源,因为在播放过程中只会从网络中提取部分内容。

下面介绍了如何在 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 正确提取和缓存您网站的媒体资源,同时考虑范围请求和与媒体请求相关的其他潜在陷阱。