PWA TypeError: Failed to fetch - javascript

I am trying to install PWA on my website. Here is my Service worker:
const CACHE_NAME = 'cache_v1';
self.addEventListener('install', async event => {
self.skipWaiting();
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
if (navigator.onLine) {
return fetch(event.request).then(function(response) {
if (event.request.method === 'GET') {
cache.put(event.request, response.clone());
}
return response;
});
} else {
return cache.match(event.request).then(function (response) {
return response;
});
}
}),
);
});
This throws me an error:
TypeError: Failed to fetch
And warning:
Site cannot be installed: Page does not work offline. Starting in Chrome 93, the installability criteria is changing, and this site will not be installable. See https://goo.gle/improved-pwa-offline-detection for more information
How can I fix them?

Happy to help brother - you have not mentioned any files to be cached but you are fetching files that's why its giving errors try mine file:
service worker.js

Related

How to prevent fetch() to ignore offline pages?

The JavaScript code below retrieves some texts from server by using Fetch API.
fetch("index.php?user_id=1234", {
method: "GET"
}).then(function(response) {
return response.text();
}).then(function(output) {
document.getElementById("output").innerHTML = output;
});
But during network errors, it retrieves the offline page (offline.html) due to service-worker.
"use strict";
self.addEventListener("install", function() {
self.skipWaiting();
});
self.addEventListener("activate", function(activation) {
activation.waitUntil(
caches.keys().then(function(cache_names) {
for (let cache_name of cache_names) {
caches.delete(cache_name);
};
caches.open("client_cache").then(function(cache) {
return cache.add("offline.html");
});
})
);
});
self.addEventListener("fetch", function(fetching) {
fetching.respondWith(
caches.match(fetching.request).then(function(cached_response) {
return cached_response || fetch(fetching.request);
}).catch(function() {
return caches.match("offline.html");
})
);
});
I want to let the fetch request know about the network error.
And I do not want to use window.navigator. So, what can I do?
(I prefer vanilla solutions.)
You should structure your service worker's fetch event handler so that it only returns offline.html when there's a network error/cache miss and the original request is for a navigation. If the original request is not a navigation, then responding with offline.html is (as you've seen) going to result in getting back HTML for every failure.
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request);
}).catch((error) => {
if (event.request.mode === 'navigate') {
return caches.match('offline.html');
}
throw error;
})
);
});

How to make service worker network first then cache

I am trying to set up pwa app. My sw.js is
var urlsToCache = [
'/danger/index.html',
'/danger/css/main.css',
'/danger/css/fontawesome-all.min.css',
'/danger/css/font.css'
];
var CACHE_NAME = 'progressive';
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open(CACHE_NAME).then(function (cache) {
return cache.match(event.request).then(function (response) {
return response || fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open(CACHE_NAME).then(function (cache) {
return fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
});
})
);
});
I want to make sw check for first network, then cache. I got a code from net.
self.addEventListener('fetch', (event) => {
event.respondWith(async function() {
try {
return await fetch(event.request);
} catch (err) {
return caches.match(event.request);
}
}());
});
How to implement it in my sw.js. I asked it because my app not updating the website content in network enabled mode also.
Browser will always reach out to network first and get the service-worker.js I would suggest you to use Workbox instead of manually writing all these code.
Workbox documentation
We should not cache service-worker file as that is a source of truth for browser to know whether any other files have changed. Usually a service-worker file will have a series of files that are cached along with their hashes. When service worker file changes, then browser knows that it needs to take update from server.
Thanks

Service Worker TypeError when opening Chrome extension

My service worker is throwing this error in Chrome when I open the WAVE (Web Accessibility Evaluation Tool) extension:
Uncaught (in promise) TypeError: Request scheme 'chrome-extension' is
unsupported
at sw.js:52 (anonymous) # sw.js:52 Promise.then (async) (anonymous) # sw.js:50 Promise.then (async) (anonymous) # sw.js:45
Promise.then (async) (anonymous) # sw.js:38
My service worker code is:
(function () {
'use strict';
var consoleLog;
var writeToConsole;
const CACHE_NAME = '20180307110051';
const CACHE_FILES = [
'https://fonts.gstatic.com/s/notosans/v6/9Z3uUWMRR7crzm1TjRicDv79_ZuUxCigM2DespTnFaw.woff2',
'https://fonts.gstatic.com/s/notosans/v6/ByLA_FLEa-16SpQuTcQn4Igp9Q8gbYrhqGlRav_IXfk.woff2',
'https://fonts.gstatic.com/s/notosans/v6/LeFlHvsZjXu2c3ZRgBq9nJBw1xU1rKptJj_0jans920.woff2',
'https://fonts.gstatic.com/s/notosans/v6/PIbvSEyHEdL91QLOQRnZ1xampu5_7CjHW5spxoeN3Vs.woff2',
'https://fonts.gstatic.com/s/materialicons/v22/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2',
'favicon.20180205072319.ico',
'favicons/android-chrome-512x512.20180211120531.png',
'favicons/android-chrome-192x192.20180211120531.png',
'offline.html'
];
// for debugging:
writeToConsole = false;
consoleLog = function (message) {
if (writeToConsole) {
console.log(message);
}
};
// https://stackoverflow.com/questions/37117933/service-workers-not-updating
self.addEventListener('install', function (e) {
e.waitUntil(
Promise.all([caches.open(CACHE_NAME), self.skipWaiting()]).then(function (storage) {
var static_cache = storage[0];
return Promise.all([static_cache.addAll(CACHE_FILES)]);
})
);
});
// intercept network requests:
self.addEventListener('fetch', function (event) {
consoleLog('Fetch event for ' + event.request.url);
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
consoleLog('Found ' + event.request.url + ' in cache');
return response;
}
consoleLog('Network request for ' + event.request.url);
// add fetched files to the cache:
return fetch(event.request.clone()).then(function (response) {
// Respond with custom 404 page
if (response.status === 404) {
return caches.match('error?status=404');
}
return caches.open(CACHE_NAME).then(function (cache) {
if (event.request.url.indexOf('test') < 0) {
cache.put(event.request.url, response.clone());
}
return response;
}).catch(function () {
console.log("Uncaught (in promise) TypeError: Request scheme 'chrome-extension' is unsupported");
});
});
}).catch(function (error) {
// respond with custom offline page:
consoleLog('Error, ' + error);
// Really need an offline page here:
return caches.match('offline.html');
})
);
});
// delete unused caches
// https://stackoverflow.com/questions/37117933/service-workers-not-updating
self.addEventListener('activate', function (e) {
e.waitUntil(
Promise.all([
self.clients.claim(),
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.map(function (cacheName) {
if (cacheName !== CACHE_NAME) {
console.log('deleting', cacheName);
return caches.delete(cacheName);
}
})
);
})
])
);
});
}());
I'm unclear on the nature of the problem and how to correct it. Many thanks in advance for help!
WAVE includes some code in your site, which then makes some request to the WAVE extension itself with an url beginning with chrome-extension://xyz. Your service intercepts this request and wants to make a fetch himself because this request is not cached. But urls with the protocol/request scheme chrome-extension:// are not allowed in service worker.
So you probably don't want to handle these WAVE requests with your service worker. Skip them with something like
if(!event.request.url.startsWith('http')){
//skip request
}
** It is because of installed chrome extension**
In my case it was wappalyzer
Any of, or all of these works.
if (
url.startsWith('chrome-extension') ||
url.includes('extension') ||
!(url.indexOf('http') === 0)
) return;
But I'm just thinking: 'can a request come from an extension that negates the above conditions'?
If yes, then how can I ensure the only successful one is that which comes from 'self'.
In my case I use chrome and extension the wappalyzer...
And I change to read and change site data to "When you click the extension"

Service worker unregistered when offline

So I've created and successfully registered a Service Worker when the browser is online. I can see that the resources are properly cached using the DevTools. The issue is when I switch to offline mode, the service worker seems to unregister itself and, as such, nothing but the google chrome offline page is displayed.
The code.
'use strict';
var CACHE_NAME = 'v1';
var urlsToCache = [
'/'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response.
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
And the test script, if that helps.
'use strict';
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
var serviceWorker;
if (registration.installing) {
serviceWorker = registration.installing;
} else if (registration.waiting) {
serviceWorker = registration.waiting;
} else if (registration.active) {
serviceWorker = registration.active;
}
if (serviceWorker) {
console.log('ServiceWorker phase:', serviceWorker.state);
serviceWorker.addEventListener('statechange', function (e) {
console.log('ServiceWorker phase:', e.target.state);
});
}
}).catch(function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
Edit: Checking the console I've found this error. sw.js:1 An unknown error occurred when fetching the script.
Aslo, as per a suggestion, I've added this code yet the problem persists.
this.addEventListener('activate', function(event) {
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
it seems you haven't added any activate event which meant to render cached elements when available. Hope the code help you.
self.addEventListener('activate', function(e) {
/*service worker activated */
e.waitUntil(
caches.key().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if(key){
//remove old cache stuffs
return caches.delete(key);
}
}));
})
);
});
The problem appears to have fixed itself. To anyone here from google, try restarting the browser.

Fetch API Error in Service Worker

I am trying to cache images from the LastFM API. Now, the API response itself is cached fine and the page loads as expected, however, there are no images.
Looking into the developer console, I can see a couple of errors regarding the retrieval of the images and they're as follows:
Fetch API cannot load http://img2-ak.lst.fm/i/u/300x300/a32cb06bb22bc5d10654a5156fe78cf6.png. The parent document page has been unloaded.
I'm very new to service workers and this has got me tearing my hair out (no, not literally).
I've followed a couple of tutorials and this is the code I've got so far (irrelevant code has been stripped out).
var CACHE_NAME = 'WELFORDIAN-CACHE-V2';
var urlsToCache = [
'https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=**USERNAME**&api_key=6136000ba0899c52db5ebcee77d4be15&format=json'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function(event) {
var reqURL = new URL(event.request.url);
if (/lst.fm/.test(reqURL)) {
event.respondWith(lastFMImageResponse(event.request));
} else {
event.respondWith(
caches.match(event.request).then(function(response) {
if (response) {
return response;
}
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
}).catch(function(err) {
return err;
})
);
}
});
function lastFMImageResponse(request) {
return caches.match(request).then(function(response) {
if (response) {
return response;
}
return fetch(request).then(function(response) {
caches.open('lfm-images').then(function(cache) {
cache.put(request, response);
});
return response.clone();
});
});
}
I'm obviously doing something wrong, but can anyone with more experience than I explain what it is?
The problem is that your website is HTTPS, while the images are served via HTTP.
Mixed content is currently not working well with service workers: https://github.com/w3c/webappsec/issues/415.

Categories