Service Worker: cache.match(request) returns undef

2019-06-21 04:44发布

I have a simple service worker, that adds two resources (index.html, app.js) to the cache (on install), deletes old caches (on activate) and serves the resources from cache if present, else from the network (on fetch). To get the new service worker registered and to delete old caches I increase the version number in CACHE_NAME with each version of new resources:

var CACHE_NAME = 'test-cache-v4';
var urlsToCache = ['./','./app.js'];

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function (cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
  return self.skipWaiting();
});

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (key !== CACHE_NAME) {
          return caches.delete(key);
        }
      }));
    }) 
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open(CACHE_NAME).then(function(cache){
      return cache.match(event.request)
        .then(function(response) {
          if (response) {
          console.log('SERVED FROM CACHE');
            return response;
          }
          return fetch(event.request).then(function(response){
              console.log('Response from network is:', response);
              return response;
          });
        }
      )
    })
  );
});

On my localhost the service worker works perfectly fine.

But on the server the response/promise returned by

return cache.match(event.request)

is always undefined. As a result the resources are never served from cache but always from network.

This happens even though in Chrome's dev tools "Application" tab I can see that registration of the new service worker works fine and "Cache Storage" gets filled with my new cache resources (request URLs to index.html and app.js). I also think that I have handled the web server config tweaks correctly with Cache-Control no-cache.

If I change

return cache.match(event.request)

to

return cache.match(event.request.url)

the service worker also works on the server.

However, I would like to understand why the syntax that seems right to me and is used in all the examples I can find does not work on the server.

One difference is that I access localhost directly and the server over https.

EDIT: Another difference is that resources from the server are compressed (Header => content-encoding:gzip).

Could it be linked to one of these differences?

Any ideas are greatly appreciated!

1条回答
别忘想泡老子
2楼-- · 2019-06-21 05:22

1. no-cache

Try to cancel cache mechanism in your server, i found these code in my remote Apache server (served over HTTPS):

<filesMatch "\.(html|htm|js|css)$">
    FileETag None
    <ifModule mod_headers.c>
        Header unset ETag
        Header append Vary User-Agent env=!dont-vary
        Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
        Header set Pragma "no-cache"
        Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
    </ifModule>
</filesMatch>

My localhost is not served over HTTPS, and the example How to Setup a Basic Service Worker works fine on it.

2. Match Method

Cache.match() - Web APIs | MDN shows that parameter should be the Request you are attempting to find in the Cache. But cache.match(event.request.url) works as well in localhost and remote Apache Server. Caching has no problem.

3. Gzip

After test in localhost(no gzip) and remote Apache server(gzip), both caching files without any error. So gzip is not one of the reason.

查看更多
登录 后发表回答