how to cache ajax response by using serviceWorker

2020-05-05 04:02发布

问题:

I am calling server data by using ajax in index.html. It is perfectly fetching those data. Now, i am working with serviceworker. I can cache all the static assets(images,js,css) and check those cached assets in Cached storage in application tab in Chrome dev tools. I can see in Network tab also those assets are cached( disk cache).

Now, I want to cache those ajax response(array of image files) using service worker. In network tab, i can see it is calling url (type : xhr ) not cached. I have tried so far to fetch the url and cache those but not able to do it.

Here is my ajax call in index.html

    <script type="text/javascript">
       $(document).ready(function () {
          var url = 'index.cfm?action=main.appcache';
            $.ajax({
                type:"GET",
                url: url,
                data: function(data){
                var resData = JSON.stringify(data);
            },
            cache: true,
            complete: doSomething
            })
});

function doSomething(data) {
    console.log(data.responseText);
}
</script>

Here is my serviceWorker fetch event:

    self.addEventListener('fetch', (event) => {

  if (event.request.mode === 'navigate') {
    event.respondWith((async () => {
      try {
        const preloadResponse = await event.preloadResponse;
        if (preloadResponse) {
          return preloadResponse;
        }
        const normalizedUrl = new URL(event.request.url);
        if(normalizedUrl.endsWith === 'index.cfm?action=main.appcache'){
           const fetchResponseP = fetch(normalizedUrl);
           const fetchResponseCloneP = fetchResponseP.then(r => r.clone());
          event.waitUntil(async function() {
           const cache = await caches.open(precacheName);
           await cache.put(normalizedUrl, await fetchResponseCloneP);
            }());
          return (await caches.match(normalizedUrl)) || fetchResponseP;
        }
        const networkResponse = await fetch(event.request);
        return networkResponse;
      } catch (error) {
        console.log('Fetch failed; returning offline page instead.', error);

        const cache = await caches.open(precacheName);
        const cachedResponse = await cache.match(offlineDefaultPage);
        return cachedResponse;
      }
    })());
  }
});

Please help me what are changes needed to cache the response.

回答1:

Your fetch event handler starts with

if (event.request.mode === 'navigate') {
  // ...
}

That means the code inside of it will only execute if the incoming fetch event is for a navigation request. Only the initial request for an HTML document when first loading a page is a navigation request. Your AJAX requests for other subresources are not navigation requests.

If you want to cache your requests for index.cfm?action=main.appcache in addition to your logic in place for navigation requests, you can add another if statement after your first one, and check for that URL:

self.addEventListener('fetch', (event) => {
  if (event.request.mode === 'navigate') {
    // ...
  }

  if (event.request.url.endsWith('index.cfm?action=main.appcache')) {
    // Your caching logic goes here. See:
    // https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook#serving-suggestions
  }
});