ServiceWorkerGlobalScope: fetch 事件

Baseline 已广泛支持

此功能已成熟,可跨多种设备和浏览器版本工作。它自 ⁨2018 年 4 月⁩ 起已在所有浏览器中可用。

安全上下文: 此功能仅在安全上下文(HTTPS)中可用,且支持此功能的浏览器数量有限。

注意:此功能仅在 Service Workers 中可用。

ServiceWorkerGlobalScope 接口的 fetch 事件在主应用程序线程发出网络请求时,在 Service Worker 的全局作用域中触发。它允许 Service Worker 拦截网络请求并发送自定义响应(例如,从本地缓存)。

此事件不可取消,也不会冒泡。

语法

在诸如 addEventListener() 之类的方法中使用事件名称,或设置事件处理程序属性。

js
addEventListener("fetch", (event) => { })

onfetch = (event) => { }

描述

当主应用程序线程发出网络请求时,fetch 事件在 Service Worker 的全局作用域中触发。这不仅包括主线程中显式的 fetch() 调用,还包括浏览器在页面导航后加载页面和子资源(如 JavaScript、CSS 和图像)的隐式网络请求。

事件处理程序会接收一个 FetchEvent 对象,该对象提供对请求的访问,请求是一个 Request 实例。

FetchEvent 还提供了一个 respondWith() 方法,该方法接受一个 Response(或解析为 ResponsePromise)作为参数。这使得 Service Worker 事件处理程序能够提供返回给主线程请求的响应。

例如,Service Worker 可以返回:

  • Cache 接口检索到的本地缓存响应。
  • Service Worker 使用诸如 Response.json() 等方法或 Response() 构造函数合成的响应。
  • 使用 Response.error() 方法的网络错误。这将导致 fetch() 调用被拒绝。

对于给定的请求,respondWith() 方法只能调用一次。如果添加了多个 fetch 事件监听器,它们将按照注册顺序调用,直到其中一个调用了 respondWith()

respondWith() 方法必须同步调用:也就是说,你不能在 then 处理程序中调用它。

通常,fetch 事件处理程序会根据请求的特征(如其 URL)执行不同的策略。

js
function strategy1() {
  return fetch("picnic.jpg");
}

function strategy2() {
  return Response.error();
}

const pattern1 = /^\/salamander/;
const pattern2 = /^\/lizard/;

self.addEventListener("fetch", (event) => {
  const url = new URL(event.request.url);
  if (pattern1.test(url.pathname)) {
    event.respondWith(strategy1());
  } else if (pattern2.test(url.pathname)) {
    event.respondWith(strategy2());
  }
});

如果在处理程序中未调用 respondWith(),则用户代理会自动发出原始网络请求。例如,在上面的代码中,所有不匹配 pattern1pattern2 的请求都像 Service Worker 不存在一样发出。

事件类型

一个 FetchEvent

示例

缓存后备网络

fetch 事件处理程序首先尝试在缓存中查找响应。如果找到响应,则返回缓存的响应。否则,它尝试从网络获取资源。

js
async function cacheThenNetwork(request) {
  const cachedResponse = await caches.match(request);
  if (cachedResponse) {
    console.log("Found response in cache:", cachedResponse);
    return cachedResponse;
  }
  console.log("Falling back to network");
  return fetch(request);
}

self.addEventListener("fetch", (event) => {
  console.log(`Handling fetch event for ${event.request.url}`);
  event.respondWith(cacheThenNetwork(event.request));
});

仅缓存

fetch 事件处理程序对脚本和样式表实现“仅缓存”策略。如果请求的 destination 属性为 "script""style",则处理程序仅在缓存中查找,如果未找到响应则返回错误。所有其他请求都将通过网络。

js
async function cacheOnly(request) {
  const cachedResponse = await caches.match(request);
  if (cachedResponse) {
    console.log("Found response in cache:", cachedResponse);
    return cachedResponse;
  }
  return Response.error();
}

self.addEventListener("fetch", (event) => {
  if (
    event.request.destination === "script" ||
    event.request.destination === "style"
  ) {
    event.respondWith(cacheOnly(event.request));
  }
});

规范

规范
Service Workers
# dom-serviceworkerglobalscope-onfetch

浏览器兼容性

另见