Skip to content

Instantly share code, notes, and snippets.

@pierophp
Last active July 21, 2022 18:05
Show Gist options
  • Save pierophp/b790ae748bb8e810abca4336424ae651 to your computer and use it in GitHub Desktop.
Save pierophp/b790ae748bb8e810abca4336424ae651 to your computer and use it in GitHub Desktop.
Cloudflare Worker - Early Hints
import * as cheerio from 'cheerio';
// Dynamic - 5 minutes
const serverMaxAgeDynamic = 60 * 5;
// Dynamic - 1 second (do not cache on browser)
const browserMaxAgeDynamic = 0;
export default {
async fetch(request: Request, env: any, ctx: ExecutionContext) {
try {
return await handleRequest(request, env, ctx);
} catch (e) {
console.error((e as any).message);
return new Response('Error thrown ' + (e as any).message);
}
},
};
async function handleRequest(
request: Request,
env: any,
ctx: ExecutionContext,
) {
const url = new URL(request.url);
let useCache = request.method === 'GET';
if (!useCache) {
let response = await fetch(url.toString(), request);
return new Response(response.body, response);
}
const cache = caches.default;
const newRequest = new Request(url.toString(), request);
let cacheKey = new Request(url.toString(), request);
let response = await cache.match(cacheKey);
if (response) {
return response;
}
return await fetchAndSaveCache(ctx, url, newRequest, cacheKey);
}
async function fetchAndSaveCache(
ctx: ExecutionContext,
url: URL,
newRequest: Request,
cacheKey: Request,
): Promise<Response> {
let fetchResponse = await fetch(url.toString(), newRequest);
// To avoid the error:
// Body has already been used. It can only be used once. Use tee() first if you need to read it twice
const [body1, body2] = fetchResponse.body?.tee()!;
// Create new object to allow modify headers
let response = new Response(body1, fetchResponse);
if (fetchResponse.status !== 200) {
return response;
}
let responseToCheerio = new Response(body2, fetchResponse);
const $ = cheerio.load(await responseToCheerio.text());
const links = $('[rel="preload"]').toArray();
// # CACHE INSIDE CLOUDFLARE
const serverMaxAge = serverMaxAgeDynamic;
// # CACHE IN THE BROWSER
const browserMaxAge = browserMaxAgeDynamic;
response.headers.delete('Cache-Control');
response.headers.set(
'Cache-Control',
`public, max-age=${browserMaxAge}, s-maxage=${serverMaxAge}`,
);
const linkHeader = links
.map(link => `<${$(link).attr('href')}>; rel="preload"`)
.join(', ');
response.headers.set('Link', linkHeader);
// To avoid the error:
// Body has already been used. It can only be used once. Use tee() first if you need to read it twice
const [body3, body4] = response.body?.tee()!;
const cache = caches.default;
// put cache only on the specific region the worker is running
ctx.waitUntil(cache.put(cacheKey, new Response(body4, response)));
return new Response(body3, response);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment