简体   繁体   中英

Service worker offline page won't load

This used to work for me but stopped a couple of months ago and I've tinkered my way right out of being able to figure this out anymore. What am I doing wrong here?

Call the service worker template, no problem:

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.');
}

Setup a cache version and preloaded the cache, no problem:

const cacheName='2020.10.06-01';

var cacheFiles = ['/offline.html'];

Installed the Services Worker, no problem:

addEventListener('install', e => {
   e.waitUntil(
       caches.open(cacheName).then(cache => {
           return cache.addAll(cacheFiles);
       })
   );
});

Activated the Services Worker for auto cache rollover, no problem:

addEventListener('activate', e => {
   e.waitUntil(
       caches.keys().then(keyList => {
           return Promise.all(keyList.map(key => {
               if(key !== cacheName) {
                   return caches.delete(key);
               }
           }));
       })
   );
});

Fetching from cache or network, no problem:

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

But if the page/resource I'm trying to request is not already in the cache AND the network is not available it refuses to display my 'offline.html' page. (Which I know IS in the cache)

Any ideas?

Replace your fetch event code with this one. For every request your fetch event will be invoked and it will check if your request is found in the cache file list then it will serve the file from there otherwise it will make the fetch call to get the file from server.

self.addEventListener("fetch", function (event) {
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                if (response) {
                    return response;
                }
                return fetch(event.request);
            })
    );
});

Also you don't need a separate "offline.html" file in your cache file list. Instead add your main application html file and your relevant css and js files in that list. That will make your application completely offline in case of no network.

Here's the Fetch code I wrote in the end that works perfectly for me:

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

This does everything I need, in a very specific order. It checks the cache first, if found it's returned. It checks the network next, if found it caches it first then returns it. Or it displays a custom offline page with a big Reload button to encourage visitors to try again when they are back online.

But the most important this to realise is that doing it this way alows me to display a page and all it's resources with or without network access.

UPDATE: In order to deal with changes to CORS security requirements that where implemented in all browsers between March and August of 2020, I had to make one small change to the 'fetch' event.

Changed from:

const fetchResponse = await fetch(event.request);

To:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM