1

I'm trying to fetch and cache some external resources/websites using a service worker.

My code in service-worker.js is the following:

'use strict';

var static_urls = [
    'https://quiqqer.local/test?app=1',
    'https://quiqqer.local/calendar?app=1'
];

self.addEventListener('install', function (event)
{
    event.waitUntil(
        caches.open('ionic-cache').then(function(cache) {
            cache.addAll(static_urls.map(function (urlToPrefetch)
            {
                console.log(urlToPrefetch);
                return new Request(urlToPrefetch, {mode: 'no-cors'});
            })).catch(function(error) {
                console.error(error);
            }).then(function() {
                console.log('All fetched and cached');
            });
        })
    );
});

Which creates this output:

service-worker.js: https://quiqqer.local/test?app=1
service-worker.js: https://quiqqer.local/calendar?app=1
service-worker.js: TypeError: failed to fetch
service-worker.js: All fetched and cached 
(index): service worker installed

What is the reason for the failing fetch?

My site https://quiqqer.local has set the header Access-Control-Allow-Origin to '*'

Maybe it's my self-signed certificate for my site?

I added an exception for this certificate, so if I open the site Chrome shows that the site isn't secure next to the URL bar but the content is still displayed.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Panni
  • 310
  • 4
  • 14
  • 1
    What do you see in the Network tab? There's more to supporting [CORS](http://www.w3.org/TR/access-control/) than just that one header. – T.J. Crowder May 09 '17 at 08:28
  • 1
    Separately: Remember that if you use `catch` and don't throw an error inside your `catch` handler or return a promise that is/will be rejected, you're converting a rejection into a resolution (which is why you see "All fetched and cached" when they aren't, in fact, all fetched and cached). – T.J. Crowder May 09 '17 at 08:28
  • Without the catch it looks like this: – Panni May 09 '17 at 08:37
  • service-worker.js:1 Uncaught (in promise) TypeError: Failed to fetch – Panni May 09 '17 at 08:37
  • In the Network tab I see the two requests but the status is "(canceled)" – Panni May 09 '17 at 08:41
  • Re the `catch`: Yes, exactly, because the fetch failed. You'd want that `catch` at the **end** of the chain, not in the middle, so it's not converting a rejection into a resolution. – T.J. Crowder May 09 '17 at 08:43
  • Re (cancelled): So have you researched the causes of seeing (cancelled) requests in the Network tab? – T.J. Crowder May 09 '17 at 08:44
  • I just had a look at chrome://net-internals/#events to see some more details about the request and there I found "net_error = -3 (ERR_ABORTED)" which according to the Chromium source code means: "An operation was aborted (due to user action)". – Panni May 09 '17 at 09:05

1 Answers1

1

Since you're explicitly setting {mode: 'no-cors'}, you're going to get back an opaque Response—one that always has a response code of 0.

cache.add() will throw a TypeError if the Response that you're attempting to add to the cache has a code outside of the 2xx range.

Because you have CORS enabled on your server, via the Access-Control-Allow-Origin header, you can just make a request with its mode set to 'cors'. 'cors' mode is the default for cross-origin URLs, so

cache.addAll(static_urls)
  .then(...)
  .catch(...);

should give you the behavior that you want.

If you were making a request against a server that didn't support CORS, and you wanted to cache it, then you'd have to explicitly set {mode: 'no-cors'} and use a combination of fetch() + cache.put() to add the opaque response the cache. (And you'd have to assume the risk that the opaque response isn't a 4xx or 5xx error, since there's no way of knowing.) But, you don't have to worry about that because your server does support CORS.

Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167