denov
denov

Reputation: 12688

Is there a way to tell if you're getting cached data from the service worker?

I'm working on an authoring / CMS type application. The application allows concurrent editing of various 'blocks' of data. It has supported offline using appache and indexDB. With this approach I know if my data is coming from the network or from the cache. Now I'd like to migrate things to use service workers and the new cache api.

I need a way to know if my data (request) was served from the cache or the network so I can inform the users they are possibly looking at stale data so any any edits may override data they don't know about. IMO, this would a pretty common thing to do but it's turning out not to be so easy...

I'm currently trying to get things working using WorkBox but I'd be more than happy with a native solution. Using Workbox I've tried to set a new header on the response but Chrome complains about

const apiStrategy = workbox.strategies.cacheFirst({
    cacheName: 'data-cache',
    cacheExpiration: {
        maxEntries: 100,
        maxAgeSeconds: 3600 * 24
    },
    cacheableResponse: { statuses: [200] }
});

workbox.routing.registerRoute(
    new RegExp('/api/'),
    async ({event, url}) => {
        const cachedResponse = await apiStrategy.handle({event, url});
        if (cachedResponse) {
            const responseClone = cachedResponse.clone();
            responseClone.headers.set('x-sw-cache', 'yes');
            return responseClone;
        }
        return cachedResponse;
    }
);

So is there any way to know if the response came from the network or the cache?

Upvotes: 3

Views: 2468

Answers (2)

denov
denov

Reputation: 12688

Turns out there's a bunch of plugins. I was able to get what I needed using the custom cacheWillUpdate plugin. My code now looks like

workbox.routing.registerRoute(
    new RegExp('/api/'),
    new workbox.strategies.NetworkFirst({
        cacheName: 'data-cache',
        cacheExpiration: {
            maxEntries: 100,
            maxAgeSeconds: 3600 * 24
        },
        cacheableResponse: { statuses: [ 200 ] },
        plugins: [
            {
                cacheWillUpdate: ({ response }) => {
                    return newResponse(response.clone(), (headers) => {
                        headers.set("x-sw-cache", 'yes');
                        return headers;
                    });
                }
            }
        ]
    })
);


const newResponse = (res, headerFn) => {
    const cloneHeaders = () => {
        const headers = new Headers();
        for (const kv of res.headers.entries()) {
            headers.append(kv[0], kv[1]);
        }
        return headers;
    };

    const headers = headerFn ? headerFn(cloneHeaders()) : res.headers;

    return new Promise((resolve) => {
        return res.blob().then((blob) => {
            resolve(new Response(blob, {
                status: res.status,
                statusText: res.statusText,
                headers: headers
            }));
        });
    });
};

The newReponse function was taken from How to alter the headers of a Response? thanks @mjs!

I can now check for the x-sw-cache header to inform my users they may be looking at state data. :)

Upvotes: 4

Matt Hasselback
Matt Hasselback

Reputation: 29

if you look in browser's dev tools (i.e. chrome) switch to the network tab it will show as (from ServiceWorker). Also if you enable debugging workbox outputs all you need to know in the console.

Upvotes: 0

Related Questions