确保您的 Service Worker 知道在请求部分响应时要执行的操作。
某些 HTTP 请求包含 Range:
标头,这表示只应返回完整资源的一部分。它们常用于流式播放音频或视频内容,允许按需加载较小的媒体块,而不是一次性请求整个远程文件。
Service Worker 是位于 Web 应用与网络之间的 JavaScript 代码,可能会拦截传出的网络请求并为其生成响应。
一直以来,范围请求和 Service Worker 并不能很好地配合。必须采取特殊措施来避免 Service Worker 出现不良结果。幸运的是,情况已经开始改变。在行为正常的浏览器中,范围请求在通过 Service Worker 传递时将“正常运行”。
具体是什么问题?
假设有一个具有以下 fetch
事件监听器的 Service Worker,它接受每个传入请求并将其传递给网络:
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
在行为不正确的浏览器中,如果 event.request
包含 Range:
标头,该标头将被静默丢弃。远程服务器收到的请求根本不包含 Range:
。这不一定会“破坏”任何内容,因为从技术层面来讲,服务器可以返回包含 200
状态代码的完整响应正文,即使原始请求中存在 Range:
标头也是如此。但会导致传输的数据比浏览器严格需要的要多。
知道此行为的开发者可以明确检查是否存在 Range:
标头,并且不调用 event.respondWith()
(如果存在)来解决此问题。这样,Service Worker 就可以有效地将自己从响应生成图片中移除,并改为使用默认的浏览器网络逻辑,该逻辑知道如何保留范围请求。
self.addEventListener('fetch', (event) => {
// Return without calling event.respondWith()
// if this is a range request.
if (event.request.headers.has('range')) {
return;
}
event.respondWith(fetch(event.request));
});
但可以肯定的是,大多数开发者都没有意识到这的必要性。并且没有明确说明为什么应该这样做。这最终是因为浏览器需要跟上底层规范的更改,从而增加了对此功能的支持。
修复了哪些内容?
当 event.request
传递给 fetch()
时,行为正常的浏览器会保留 Range:
标头。这意味着,如果浏览器设置了 Range:
标头,我的初始示例中的 Service Worker 代码将允许远程服务器查看该标头:
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
服务器现在有机会正确处理范围请求,并返回带有 206
状态代码的部分响应。
哪些浏览器能正常运行?
最新版本的 Safari 具有正确的功能。从 87 版开始,Chrome 和 Edge 也可以正常运行。
截至 2020 年 10 月,Firefox 尚未修复此行为,因此在将 Service Worker 的代码部署到生产环境时,您可能仍需考虑此问题。
查看 Web 平台测试信息中心的“在网络请求中包含范围标头”行是确认给定浏览器是否已纠正此行为的最佳方式。
如何处理来自缓存的范围请求?
Service Worker 不仅可以将请求传递到网络,一种常见用例是将音频和视频文件等资源添加到本地缓存。然后,Service Worker 就可以完全绕过网络来执行来自该缓存的请求。
包括 Firefox 在内的所有浏览器都支持在 fetch
处理程序内检查请求,检查是否存在 Range:
标头,然后使用来自缓存的 206
响应在本地执行该请求。不过,用于正确解析 Range:
标头并仅返回完整缓存响应的适当片段的 Service Worker 代码并非易事。
幸运的是,开发者如果需要帮助,可以求助于 Workbox,这是一组可简化 Service Worker 常见用例的库。workbox-range-request module
实现了直接从缓存提供部分响应所需的所有逻辑。如需查看此用例的完整方案,请参阅 Workbox 文档。
本博文的主打图片由 Natalie Rhea Riggs 在 Unsplash 发布。