如何从缓存中加载不同的文件?
How to load different files from cache?
我正在使用 Service Worker 提供显示用户离线的后备页面。 Service Worker 在拦截请求期间获取相同的请求,并在获取错误时从缓存中为 'offline.html' 请求提供响应。这样做的一个小片段是。
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then(() => {
return fetch(event.request).catch((err) => {
return caches.match("offline.html");
});
})
);
});
现在,如果离线 html 有其他请求,可能是对其 css 文件或图像的请求,我该如何从缓存中加载它们。我试过执行以下操作:
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then(() => {
return fetch(event.request).catch((err) => {
let url = event.request.url;
if(url.endsWith('.css')) return caches.match('offline.css');
if(url.endsWith('.jpg') || url.endsWith('.png')) return caches.match('images/banner.jpg');
return caches.match("offline.html");
});
})
);
});
但是有更好的方法吗?有这样做的标准方法吗?
首先,我建议您在决定是否使用 offline.html
作为后备内容之前检查是否 event.request.destination === 'document'
。这确保您不会意外返回 HTML 文档来满足,比如说,碰巧失败的随机 API 请求。
此外,您当前的代码包括 caches.match(event.request)
但实际上并没有使用缓存的响应,这可能不是您想要的。
也就是说,让我们来看看我认为是您想要的逻辑:
- 您的服务工作者尝试对网络发出请求。
- 如果该请求 returns 有效响应,使用它,您就完成了。
- 如果该请求失败,则:
- 如果是导航请求,无论目的地如何 URL,请使用缓存的
offline.html
作为响应。
- 否则,对于非导航请求(如 CSS 或 JS 请求),使用匹配所需 URL 的缓存条目作为响应。
这是实现它的服务工作者。您需要确保 CSS、JS 和 offline.html
资产是 cached during service worker installation;这只包括 fetch
处理程序逻辑。
self.addEventListener('install', (event) => {
event.waitUntil(
/* Cache your offline.html and the CSS and JS it uses here. */
);
});
async function fetchLogic(request) {
try {
// If the network request succeeds, just use
// that as the response.
return await fetch(request);
} catch(error) {
// Otherwise, implement fallback logic.
if (request.mode === 'navigate') {
// Use the cached fallback.html for failed navigations.
return await caches.match('offline.html');
}
// Otherwise, return a cached copy of the actual
// subresource that was requested.
// If there's a cache miss for that given URL, you'll
// end up with a NetworkError, just like you would if
// there were no service worker involvement.
return await caches.match(request.url);
}
}
self.addEventListener('fetch', (event) => {
event.respondWith(fetchLogic(event.request));
});
this article 中也有一些正式的指导。
我正在使用 Service Worker 提供显示用户离线的后备页面。 Service Worker 在拦截请求期间获取相同的请求,并在获取错误时从缓存中为 'offline.html' 请求提供响应。这样做的一个小片段是。
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then(() => {
return fetch(event.request).catch((err) => {
return caches.match("offline.html");
});
})
);
});
现在,如果离线 html 有其他请求,可能是对其 css 文件或图像的请求,我该如何从缓存中加载它们。我试过执行以下操作:
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then(() => {
return fetch(event.request).catch((err) => {
let url = event.request.url;
if(url.endsWith('.css')) return caches.match('offline.css');
if(url.endsWith('.jpg') || url.endsWith('.png')) return caches.match('images/banner.jpg');
return caches.match("offline.html");
});
})
);
});
但是有更好的方法吗?有这样做的标准方法吗?
首先,我建议您在决定是否使用 offline.html
作为后备内容之前检查是否 event.request.destination === 'document'
。这确保您不会意外返回 HTML 文档来满足,比如说,碰巧失败的随机 API 请求。
此外,您当前的代码包括 caches.match(event.request)
但实际上并没有使用缓存的响应,这可能不是您想要的。
也就是说,让我们来看看我认为是您想要的逻辑:
- 您的服务工作者尝试对网络发出请求。
- 如果该请求 returns 有效响应,使用它,您就完成了。
- 如果该请求失败,则:
- 如果是导航请求,无论目的地如何 URL,请使用缓存的
offline.html
作为响应。 - 否则,对于非导航请求(如 CSS 或 JS 请求),使用匹配所需 URL 的缓存条目作为响应。
- 如果是导航请求,无论目的地如何 URL,请使用缓存的
这是实现它的服务工作者。您需要确保 CSS、JS 和 offline.html
资产是 cached during service worker installation;这只包括 fetch
处理程序逻辑。
self.addEventListener('install', (event) => {
event.waitUntil(
/* Cache your offline.html and the CSS and JS it uses here. */
);
});
async function fetchLogic(request) {
try {
// If the network request succeeds, just use
// that as the response.
return await fetch(request);
} catch(error) {
// Otherwise, implement fallback logic.
if (request.mode === 'navigate') {
// Use the cached fallback.html for failed navigations.
return await caches.match('offline.html');
}
// Otherwise, return a cached copy of the actual
// subresource that was requested.
// If there's a cache miss for that given URL, you'll
// end up with a NetworkError, just like you would if
// there were no service worker involvement.
return await caches.match(request.url);
}
}
self.addEventListener('fetch', (event) => {
event.respondWith(fetchLogic(event.request));
});
this article 中也有一些正式的指导。