在 Service Worker 中检测离线状态的最佳实践
Best practices for detecting offline state in a service worker
我有一个 service worker,它应该缓存一个 offline.html
页面,如果客户端没有网络连接则显示该页面。但是,它有时会认为导航器处于离线状态,即使它并未离线。即navigator.onLine === false
。这意味着即使在线,用户也可能获得 offline.html
而不是实际内容,这显然是我想避免的事情。
这就是我在 main.js
中注册 Service Worker 的方式:
// Install service worker for offline use and caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {scope: '/'});
}
我现在的 service-worker.js
:
const OFFLINE_URL = '/mysite/offline';
const CACHE_NAME = 'mysite-static-v1';
self.addEventListener('install', (event) => {
event.waitUntil(
// Cache the offline page when installing the service worker
fetch(OFFLINE_URL, { credentials: 'include' }).then(response =>
caches.open(CACHE_NAME).then(cache => cache.put(OFFLINE_URL, response)),
),
);
});
self.addEventListener('fetch', (event) => {
const requestURL = new URL(event.request.url);
if (requestURL.origin === location.origin) {
// Load static assets from cache if network is down
if (/\.(css|js|woff|woff2|ttf|eot|svg)$/.test(requestURL.pathname)) {
event.respondWith(
caches.open(CACHE_NAME).then(cache =>
caches.match(event.request).then((result) => {
if (navigator.onLine === false) {
// We are offline so return the cached version immediately, null or not.
return result;
}
// We are online so let's run the request to make sure our content
// is up-to-date.
return fetch(event.request).then((response) => {
// Save the result to cache for later use.
cache.put(event.request, response.clone());
return response;
});
}),
),
);
return;
}
}
if (event.request.mode === 'navigate' && navigator.onLine === false) {
// Uh-oh, we navigated to a page while offline. Let's show our default page.
event.respondWith(caches.match(OFFLINE_URL));
return;
}
// Passthrough for everything else
event.respondWith(fetch(event.request));
});
我做错了什么?
navigator.onLine
和相关事件在您想要更新 UI 以指示您处于离线状态时非常有用,例如,仅显示存在于缓存中的内容。
但我会避免编写依赖于检查 navigator.onLine
的服务工作者逻辑。相反,请尝试无条件地发出 fetch()
,如果失败,请提供备份响应。这将确保您的 Web 应用程序按预期运行,无论 fetch()
是由于离线、lie-fi 还是由于您的 Web 服务器遇到问题而失败。
// Other fetch handler code...
if (event.request.mode === 'navigate') {
return event.respondWith(
fetch(event.request).catch(() => caches.match(OFFLINE_URL))
);
}
// Other fetch handler code...
我有一个 service worker,它应该缓存一个 offline.html
页面,如果客户端没有网络连接则显示该页面。但是,它有时会认为导航器处于离线状态,即使它并未离线。即navigator.onLine === false
。这意味着即使在线,用户也可能获得 offline.html
而不是实际内容,这显然是我想避免的事情。
这就是我在 main.js
中注册 Service Worker 的方式:
// Install service worker for offline use and caching
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {scope: '/'});
}
我现在的 service-worker.js
:
const OFFLINE_URL = '/mysite/offline';
const CACHE_NAME = 'mysite-static-v1';
self.addEventListener('install', (event) => {
event.waitUntil(
// Cache the offline page when installing the service worker
fetch(OFFLINE_URL, { credentials: 'include' }).then(response =>
caches.open(CACHE_NAME).then(cache => cache.put(OFFLINE_URL, response)),
),
);
});
self.addEventListener('fetch', (event) => {
const requestURL = new URL(event.request.url);
if (requestURL.origin === location.origin) {
// Load static assets from cache if network is down
if (/\.(css|js|woff|woff2|ttf|eot|svg)$/.test(requestURL.pathname)) {
event.respondWith(
caches.open(CACHE_NAME).then(cache =>
caches.match(event.request).then((result) => {
if (navigator.onLine === false) {
// We are offline so return the cached version immediately, null or not.
return result;
}
// We are online so let's run the request to make sure our content
// is up-to-date.
return fetch(event.request).then((response) => {
// Save the result to cache for later use.
cache.put(event.request, response.clone());
return response;
});
}),
),
);
return;
}
}
if (event.request.mode === 'navigate' && navigator.onLine === false) {
// Uh-oh, we navigated to a page while offline. Let's show our default page.
event.respondWith(caches.match(OFFLINE_URL));
return;
}
// Passthrough for everything else
event.respondWith(fetch(event.request));
});
我做错了什么?
navigator.onLine
和相关事件在您想要更新 UI 以指示您处于离线状态时非常有用,例如,仅显示存在于缓存中的内容。
但我会避免编写依赖于检查 navigator.onLine
的服务工作者逻辑。相反,请尝试无条件地发出 fetch()
,如果失败,请提供备份响应。这将确保您的 Web 应用程序按预期运行,无论 fetch()
是由于离线、lie-fi 还是由于您的 Web 服务器遇到问题而失败。
// Other fetch handler code...
if (event.request.mode === 'navigate') {
return event.respondWith(
fetch(event.request).catch(() => caches.match(OFFLINE_URL))
);
}
// Other fetch handler code...