Shirokawa
Shirokawa
Explore posts from servers
CDCloudflare Developers
Created by Shirokawa on 7/26/2023 in #workers-help
Using Cache API with gzipped R2 object
Hi! I am trying to use the Cache API for a response that contains a gzip encoded html file (persisted in R2) as the response body. The Worker uses a custom domain. The problem is, when trying to return the body as a ReadableStream (see code below), cache match stops returning anything and the full code evaluates every time. I have verified that the Cache works as expected when I decompress the body before returning it as the response body. The code looks roughly like this (some business logic removed for brevity):
export interface Env {
R2: R2Bucket;
}

interface CustomExportedHandler extends Omit<ExportedHandler, "fetch"> {
fetch: ExportedHandlerFetchHandler<Env, unknown>;
}

const handler: CustomExportedHandler = {
async fetch(request, { R2 }, ctx): Promise<Response> {
try {
const url = new URL(request.url);

const cacheKey = `https://${url.hostname}${url.pathname}`;
const cacheMaxAge = 60 * 15; // 15 min
const cache = caches.default;

const cachedPage = await cache.match(cacheKey);

let response = new Response(cachedPage?.body, cachedPage);
// Set Cache-Control headers (otherwise default from Cloudflare is 4h)
response.headers.set("Cache-Control", `s-maxage=${cacheMaxAge}`);

if (!response) {
const r2Object = await R2.get(url.pathname);
if (!r2Object) throw Error("No page data.");

response = new Response(r2Object.body, {
...response,
encodeBody: "manual",
});
response.headers.set("content-encoding", "gzip");
response.headers.set("content-type", "text/html;charset=utf-8");

ctx.waitUntil(cache.put(cacheKey, response.clone()));
}
return response;
} catch (e: unknown) {
if (e instanceof Error) {
console.error(`Error requesting: ${request.url}\n -> ${e.message}`);
}
return new Response("Not found", { status: 404 });
}
},
};

export default handler;
export interface Env {
R2: R2Bucket;
}

interface CustomExportedHandler extends Omit<ExportedHandler, "fetch"> {
fetch: ExportedHandlerFetchHandler<Env, unknown>;
}

const handler: CustomExportedHandler = {
async fetch(request, { R2 }, ctx): Promise<Response> {
try {
const url = new URL(request.url);

const cacheKey = `https://${url.hostname}${url.pathname}`;
const cacheMaxAge = 60 * 15; // 15 min
const cache = caches.default;

const cachedPage = await cache.match(cacheKey);

let response = new Response(cachedPage?.body, cachedPage);
// Set Cache-Control headers (otherwise default from Cloudflare is 4h)
response.headers.set("Cache-Control", `s-maxage=${cacheMaxAge}`);

if (!response) {
const r2Object = await R2.get(url.pathname);
if (!r2Object) throw Error("No page data.");

response = new Response(r2Object.body, {
...response,
encodeBody: "manual",
});
response.headers.set("content-encoding", "gzip");
response.headers.set("content-type", "text/html;charset=utf-8");

ctx.waitUntil(cache.put(cacheKey, response.clone()));
}
return response;
} catch (e: unknown) {
if (e instanceof Error) {
console.error(`Error requesting: ${request.url}\n -> ${e.message}`);
}
return new Response("Not found", { status: 404 });
}
},
};

export default handler;
1 replies