I created a Service Worker that caches the results of nearmap and metromap tiles for a longer period of time. See below code.
const version = 10;
const CACHE_NAME = `mapbox-tiles-nearmap-${version}`;
const periodForTiles = (1000 * 60 * 60 * 24 * 356) / 2; // half year
const listResorcesForCache = ['api.nearmap.com/tiles', 'api-v3.metromap.com.au/tiles'];
self.addEventListener('fetch', event => {
if (isCachedResource(event.request.url)) {
event.respondWith(fromCacheOrNetwork(event.request));
} else {
event.respondWith(fromNetwork(event.request));
}
});
async function fromCacheOrNetwork(request) {
const cache = await caches.open(CACHE_NAME);
const response = await cache.match(request, {ignoreVary: true});
console.log('test', {cache, response});
// @todo: this is where the issue is, the response is always undefined
return isFresh(response) ? response : fromNetwork(request);
}
function fromNetwork(request) {
return fetch(request.clone())
.then(function (response) {
if (isCachedResource(request.url) && response.status < 300) {
cachePut(request, response);
}
return response;
})
.catch(function (error) {
// This catch() will handle exceptions that arise from the match() or fetch() operations.
// Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
// It will return a normal response object that has the appropriate error code set.
console.error(' Error in fetch handler:', error);
throw error;
});
}
async function cachePut(request, response) {
const options = {
status: response.status,
statusText: response.statusText,
headers: new Headers(),
};
response.headers.forEach((v, k) => options.headers.set(k, v));
options.headers.set(
'Expires',
new Date(Date.now() + periodForTiles).toUTCString()
);
const clonedResponse = response.clone();
const cache = await caches.open(CACHE_NAME);
cache.put(request, new Response(clonedResponse.body, options));
}
function isFresh(response) {
if (!response) return false;
const expires = new Date(response.headers.get('Expires'));
return expires > Date.now();
}
function isCachedResource(url) {
return (
undefined !==
listResorcesForCache.find(item => {
return url.includes(item);
})
);
}
Currently, the code is able to intercept the fetch requests from nearmap and metrop and store the result to Cache Storage. However, when I to fetch from cache, it is always returning “undefined” based on the result returned from cache.match()
. Any idea why it’s able to store but not able to retrieve?
I have tried adding ignoreVary
option on the cache.match()
function but it still returned undefined.
New contributor