FetchEvent.respondWith()

FetchEvent 接口的 respondWith() 方法阻止浏览器默认的 fetch 操作,并且允许由你自己为 Response 提供一个 promise。

在大多数情况下,你可以提供接收方理解的任何形式的响应。例如,如果是由 <img> 初始化的请求,起响应主体必须是图像数据。出于安全考虑,这里有一些全局的规则:

指定资源的最终 URL

从 Firefox 59 开始,在 service worker 中向 FetchEvent.respondWith() 提供 Response 时,Response.url 的值将作为最终解析的 URL 传输给被拦截的网络请求。如果 Response.url 值是空的字符串,那么 FetchEvent.request.url 将被用作最终的 URL。

过去,在所有情况下,一直使用 FetchEvent.request.url 作为最终的 URL。提供的 Response.url 实际上被忽略了。

例如,这意味着,如果 service worker 拦截了一个样式表或者 worker 脚本,那么提供的 Response.url 将会用于解决任何与 @importimportScripts() 相关的子资源加载(Firefox bug 1222008)。

对于大多数网络请求的类型,此变更是没有影响的,因为你不能察觉到最终的 URL。然而,在一些方面确实很重要:

  • 如果 fetch() 被拦截,那么你可以在结果的 Response.url 观察最终的结果。
  • 如果 worker 脚本被拦截,那么最终的 URL 将用于设置 self.location 并用作 worker 脚本相对 URL 的基本 URL。
  • 如果样式表被拦截,那么最终 URL 被用作解决相对 @import 加载的基本 URL。

请注意 Windowsiframes 的导航请求不使用最终的 URL。HTML 规范处理导航重定向的方式是最终使用 Window.location 生成的请求 URL。这意味着网站在离线时仍然可以提供一个“备用”的网页视图,而无需更改用户可见的 URL。

语法

js
respondWith(response)

参数

response

一个 Response 或者 Promise(兑现为一个 Response)。否则,Fetch 返回一个网络错误。

返回值

无(undefined)。

异常

NetworkError DOMException

如果 FetchEvent.request.modeResponse.type 值的某些组合触发网络错误,正如上面提到的“全局规则”,则返回该错误。

InvalidStateError DOMException

如果事件仍没有被派发或者 respondWith() 已经被调用,则返回该错误。

示例

这个 fetch 事件尝试从 cache API 返回一个响应,否则回落至网络请求。

js
addEventListener("fetch", (event) => {
  // Prevent the default, and handle the request ourselves.
  event.respondWith(
    (async () => {
      // Try to get the response from a cache.
      const cachedResponse = await caches.match(event.request);
      // Return it if we found one.
      if (cachedResponse) return cachedResponse;
      // If we didn't find a match in the cache, use the network.
      return fetch(event.request);
    })(),
  );
});

备注: caches.match() 是一个语法糖。等效于在每个缓存上调用 cache.match()(按照 caches.keys() 的顺序)直到返回 Response

规范

Specification
Service Workers
# fetch-event-respondwith

浏览器兼容性

BCD tables only load in the browser

参见