Cloudflare Workers Caching API

caching

#1

I’m having some troubles getting the Cloudflare Worker caching API to behave as I would expect. My example worker code is as follows:

'use strict';
/* eslint-disable node/no-unsupported-features/es-syntax, node/no-unsupported-features/node-builtins */

addEventListener('fetch', event => {
	event.respondWith(handleRequest(event));
});

const expiration = 43200; // 12 hours

async function handleRequest(event){
	let cache = caches.default;
	let response = await cache.match(event.request);
	if(!response){
		let tempReq = await fetch('https://randomuser.me/api/');
		let returnHdrs = new Headers();
		returnHdrs.set('Content-Type', 'application/json');
		returnHdrs.set('Cache-Control', "public, max-age=" + expiration);
		returnHdrs.set('Expires', new Date(Date.now() + expiration * 1000).toUTCString());
		let tempResponse = await tempReq.json();
		response = new Response(JSON.stringify({
			user: tempResponse.results && tempResponse.results[0] || 'unknown'
		}), {
			status: tempReq.status,
			statusText: tempReq.statusText,
			headers: returnHdrs
		});
	}
	event.waitUntil(cache.put(event.request, response.clone()));
	return response;
}

This is very stripped down, but illustrates my point. I’m trying to request data from an external source, manipulate it slightly and use parts of it, and then return my own JSON data, with Cloudflare caching it for ~12 hours. No matter what I try, I can not get the CF-Cache-Status header to appear.

What am I doing wrong?


#2

Hi @cherryjimbo,

Are you seeing this behavior in production, with a deployed script? Or only in the preview? (I ask because the preview service does not currently implement the Cache API.)

I tried deploying the script you posted on one of my routes and it worked on the first try, without modification.

I have a couple bits of feedback on the script:

  • The Cache-Control header takes precedence over Expires, so setting Expires should be unnecessary.
  • cache.put()ing the response even when it was already cached will needlessly overwrite the existing cached response. Better to put that line inside the if (!response) block.

Neither of those two issues would explain why it’s not working, though.

Harris


#3

It’s a deployed script, specifically to -snip- if you wish to investigate. Doing a curl -I -snip- doesn’t present any CF-Cache-Status header as I would expect.

Good feedback though - I’ve modified the script with those changes, but am definitely still seeing the issue described.


#4

Actually, nevermind. I just tested with curl -vs "https://jamesross.name/test" and see the header exactly as expected. It appears that doing a HEAD with -I simply doesn’t return the header.

Thanks!


#5

You’re right, the Cache API does not allow matching HEAD requests – cache.match() returns a promise for undefined in this case.

It does this because that’s what the Service Worker spec prescribes. However, it seems like we ought to deviate from the spec here – I’ll explore the possibility of relaxing this restriction.

Harris