Last active
July 21, 2022 18:05
-
-
Save pierophp/b790ae748bb8e810abca4336424ae651 to your computer and use it in GitHub Desktop.
Cloudflare Worker - Early Hints
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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