Service Worker 离线页面无法加载
Service worker offline page won't load
这曾经对我有用,但几个月前就停止了,我已经修改了自己的方法,无法再解决这个问题。我在这里做错了什么?
调用service worker模板,没问题:
if(navigator.serviceWorker){
window.addEventListener('load',() => {
navigator.serviceWorker
.register('/sw.js')
.then(console.log('[ServiceWorker] Registered Successfully'))
.catch(err => console.log(`[ServiceWorker] Error: ${err}`));
});
} else {
console.log('Service Worker not supported.');
}
设置缓存版本并预加载缓存,没问题:
const cacheName='2020.10.06-01';
var cacheFiles = ['/offline.html'];
安装了 Services Worker,没问题:
addEventListener('install', e => {
e.waitUntil(
caches.open(cacheName).then(cache => {
return cache.addAll(cacheFiles);
})
);
});
为自动缓存翻转激活了 Services Worker,没问题:
addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if(key !== cacheName) {
return caches.delete(key);
}
}));
})
);
});
正在从缓存或网络中获取,没有问题:
addEventListener('fetch', e => {
e.respondWith(async function() {
try {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(e.request);
const networkResponsePromise = fetch(e.request);
e.waitUntil(async function() {
const networkResponse = await networkResponsePromise;
await cache.put(e.request, networkResponse.clone());
}());
// Returned the cached response if we have one, otherwise return the network response.
return cachedResponse || networkResponsePromise;
} catch (error) {
console.log('Fetch failed; returning offline page instead.', error);
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match('/offline.html');
return cachedResponse;
}
}());
});
但是如果我尝试请求的 page/resource 不在缓存中并且网络不可用,它会拒绝显示我的 'offline.html' 页面。 (我知道它在缓存中)
有什么想法吗?
用这个替换您的获取事件代码。对于每个请求,你的 fetch 事件都会被调用,它会检查你的请求是否在缓存文件列表中,然后它会从那里提供文件,否则它会进行 fetch 调用以从服务器获取文件。
self.addEventListener("fetch", function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});
此外,您的缓存文件列表中也不需要单独的“offline.html”文件。而是在该列表中添加您的主应用程序 html 文件和相关的 css 和 js 文件。这将使您的应用程序在没有网络的情况下完全离线。
这是我最后编写的非常适合我的 Fetch 代码:
self.addEventListener('fetch', (event) => {
event.respondWith((async() => {
const cache = await caches.open(cacheName);
try {
const cachedResponse = await cache.match(event.request);
if(cachedResponse) {
console.log('cachedResponse: ', event.request.url);
return cachedResponse;
}
const fetchResponse = await fetch(event.request);
if(fetchResponse) {
console.log('fetchResponse: ', event.request.url);
await cache.put(event.request, fetchResponse.clone());
return fetchResponse;
}
} catch (error) {
console.log('Fetch failed: ', error);
const cachedResponse = await cache.match('/en/offline.html');
return cachedResponse;
}
})());
});
这按照非常具体的顺序完成了我需要的一切。它首先检查缓存,如果找到则返回。接下来它检查网络,如果发现它首先缓存它然后 returns 它。或者它会显示一个带有大重新加载按钮的自定义离线页面,以鼓励访问者在他们重新在线时重试。
但最重要的是要意识到,这样做可以让我在有或没有网络访问的情况下显示页面及其所有资源。
更新:为了应对 2020 年 3 月至 8 月期间在所有浏览器中实施的 CORS 安全要求的变化,我不得不对 'fetch' 事件进行一个小改动。
更改自:
const fetchResponse = await fetch(event.request);
收件人:
const fetchResponse = await fetch(event.request, {mode:'no-cors'});
这曾经对我有用,但几个月前就停止了,我已经修改了自己的方法,无法再解决这个问题。我在这里做错了什么?
调用service worker模板,没问题:
if(navigator.serviceWorker){
window.addEventListener('load',() => {
navigator.serviceWorker
.register('/sw.js')
.then(console.log('[ServiceWorker] Registered Successfully'))
.catch(err => console.log(`[ServiceWorker] Error: ${err}`));
});
} else {
console.log('Service Worker not supported.');
}
设置缓存版本并预加载缓存,没问题:
const cacheName='2020.10.06-01';
var cacheFiles = ['/offline.html'];
安装了 Services Worker,没问题:
addEventListener('install', e => {
e.waitUntil(
caches.open(cacheName).then(cache => {
return cache.addAll(cacheFiles);
})
);
});
为自动缓存翻转激活了 Services Worker,没问题:
addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if(key !== cacheName) {
return caches.delete(key);
}
}));
})
);
});
正在从缓存或网络中获取,没有问题:
addEventListener('fetch', e => {
e.respondWith(async function() {
try {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(e.request);
const networkResponsePromise = fetch(e.request);
e.waitUntil(async function() {
const networkResponse = await networkResponsePromise;
await cache.put(e.request, networkResponse.clone());
}());
// Returned the cached response if we have one, otherwise return the network response.
return cachedResponse || networkResponsePromise;
} catch (error) {
console.log('Fetch failed; returning offline page instead.', error);
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match('/offline.html');
return cachedResponse;
}
}());
});
但是如果我尝试请求的 page/resource 不在缓存中并且网络不可用,它会拒绝显示我的 'offline.html' 页面。 (我知道它在缓存中)
有什么想法吗?
用这个替换您的获取事件代码。对于每个请求,你的 fetch 事件都会被调用,它会检查你的请求是否在缓存文件列表中,然后它会从那里提供文件,否则它会进行 fetch 调用以从服务器获取文件。
self.addEventListener("fetch", function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});
此外,您的缓存文件列表中也不需要单独的“offline.html”文件。而是在该列表中添加您的主应用程序 html 文件和相关的 css 和 js 文件。这将使您的应用程序在没有网络的情况下完全离线。
这是我最后编写的非常适合我的 Fetch 代码:
self.addEventListener('fetch', (event) => {
event.respondWith((async() => {
const cache = await caches.open(cacheName);
try {
const cachedResponse = await cache.match(event.request);
if(cachedResponse) {
console.log('cachedResponse: ', event.request.url);
return cachedResponse;
}
const fetchResponse = await fetch(event.request);
if(fetchResponse) {
console.log('fetchResponse: ', event.request.url);
await cache.put(event.request, fetchResponse.clone());
return fetchResponse;
}
} catch (error) {
console.log('Fetch failed: ', error);
const cachedResponse = await cache.match('/en/offline.html');
return cachedResponse;
}
})());
});
这按照非常具体的顺序完成了我需要的一切。它首先检查缓存,如果找到则返回。接下来它检查网络,如果发现它首先缓存它然后 returns 它。或者它会显示一个带有大重新加载按钮的自定义离线页面,以鼓励访问者在他们重新在线时重试。
但最重要的是要意识到,这样做可以让我在有或没有网络访问的情况下显示页面及其所有资源。
更新:为了应对 2020 年 3 月至 8 月期间在所有浏览器中实施的 CORS 安全要求的变化,我不得不对 'fetch' 事件进行一个小改动。
更改自:
const fetchResponse = await fetch(event.request);
收件人:
const fetchResponse = await fetch(event.request, {mode:'no-cors'});