【问题标题】:Service worker offline page won't loadService Worker 离线页面无法加载
【发布时间】:2020-10-06 22:07:23
【问题描述】:

这曾经对我有用,但几个月前停止了,我已经修补了自己的方式,无法再解决这个问题。我在这里做错了什么?

调用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;
        }
    }());
});

但是,如果我尝试请求的页面/资源尚未在缓存中并且网络不可用,它将拒绝显示我的“offline.html”页面。 (我知道它在缓存中)

有什么想法吗?

【问题讨论】:

    标签: javascript service-worker


    【解决方案1】:

    用这个替换您的 fetch 事件代码。对于每个请求,都会调用您的 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 文件。这将使您的应用程序在没有网络的情况下完全脱机。

    【讨论】:

      【解决方案2】:

      这是我最后编写的非常适合我的 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;
          }
        })());
      });
      

      这可以按照非常具体的顺序完成我需要的一切。它首先检查缓存,如果找到则返回。它接下来检查网络,如果发现它首先缓存它然后返回它。或者,它会显示一个自定义离线页面,并带有一个大的“重新加载”按钮,以鼓励访问者在他们重新在线时再试一次。

      但要意识到的最重要的一点是,这样做可以让我在有或没有网络访问的情况下显示页面及其所有资源。

      更新:为了应对 2020 年 3 月至 8 月期间在所有浏览器中实施的 CORS 安全要求的更改,我不得不对“获取”事件进行一点小改动。

      更改自:

      const fetchResponse = await fetch(event.request);
      

      收件人:

      const fetchResponse = await fetch(event.request, {mode:'no-cors'});
      

      【讨论】:

        猜你喜欢
        • 2020-02-19
        • 1970-01-01
        • 1970-01-01
        • 2017-12-26
        • 2017-07-06
        • 2020-05-18
        • 2017-05-18
        • 2021-01-23
        • 2020-06-09
        相关资源
        最近更新 更多