H
Hono4w ago
timkelty

How to middleware to recursive fetches (ESI subrequests)

Gist
Hono ESI
Hono ESI. GitHub Gist: instantly share code, notes, and snippets.
7 Replies
Arjix
Arjix4w ago
Yeah I can see a number of issues already. I'll leave a review later (just got off work)
timkelty
timkeltyOP4w ago
Thanks!
Arjix
Arjix4w ago
the gist feels incomplete where is the ESI at? ok, so the error you are talking about in the comment, is most likely because you are registering middleware after the app has "initialised", so to speak I see what you meant by nested Hono I imagine something akin to this is what you are looking for
import { Hono } from 'hono'
import { proxy } from 'hono/proxy'
import ESI from "cloudflare-esi";

const resources = new Hono<{
Bindings: CloudflareBindings;
Variables: ContextVariables;
}>()
.use(timing())
.use(cache({ cacheName: "origin-cache" }))
.get("*", (ctx) => {
const { environmentId, originUrl } = ctx.get("kvData");
const { hostname, pathname, search } = new URL(ctx.req.url)

return proxy(new URL(`${pathname}${search}`, originUrl), {
headers: {
...ctx.req.header(),
'x-forwarded-for': ctx.req.header('cf-connecting-ip'),
'x-forwarded-host': hostname,
},
cf: {
cacheTags: [ environmentId ]
}
});
})
;

const app = new Hono<{
Bindings: CloudflareBindings;
Variables: ContextVariables;
}>()
.use(contextStorage())
.use(logger())
.use(timeout(maxDurationMs))
.use(sizeLimit(maxBytes))
.use(timing())
.get("*", (ctx) => {
const esi = new ESI(undefined, undefined, (req) => resources.fetch(req, ctx.env));
return await esi.parse(ctx.req.raw.clone());
})
;

export default app;
import { Hono } from 'hono'
import { proxy } from 'hono/proxy'
import ESI from "cloudflare-esi";

const resources = new Hono<{
Bindings: CloudflareBindings;
Variables: ContextVariables;
}>()
.use(timing())
.use(cache({ cacheName: "origin-cache" }))
.get("*", (ctx) => {
const { environmentId, originUrl } = ctx.get("kvData");
const { hostname, pathname, search } = new URL(ctx.req.url)

return proxy(new URL(`${pathname}${search}`, originUrl), {
headers: {
...ctx.req.header(),
'x-forwarded-for': ctx.req.header('cf-connecting-ip'),
'x-forwarded-host': hostname,
},
cf: {
cacheTags: [ environmentId ]
}
});
})
;

const app = new Hono<{
Bindings: CloudflareBindings;
Variables: ContextVariables;
}>()
.use(contextStorage())
.use(logger())
.use(timeout(maxDurationMs))
.use(sizeLimit(maxBytes))
.use(timing())
.get("*", (ctx) => {
const esi = new ESI(undefined, undefined, (req) => resources.fetch(req, ctx.env));
return await esi.parse(ctx.req.raw.clone());
})
;

export default app;
I am not able to test this as I do not know the worker stuff @timkelty (wrote that code using notepad, so it might have errors)
timkelty
timkeltyOP4w ago
Look right! I’ll give it a shot Although…ideally I wanted mw after the esi stuff too timing specifically (for the whole request) I guess I could just do that with the app.get, right? Why the app.get('*') vs use? Wont that only match GET reqs?
Arjix
Arjix4w ago
You want to cache the response, that only makes sense when it's a GET request. Why would you cache the response for say a POST request? Also, .use is for middleware only If you want to handle multiple http verbs, use .on .on(["GET", "POST"], "*", (ctx) => {})
timkelty
timkeltyOP4w ago
I only want to cache GETs, yes – but I still need everything running through parser.
.use is for middleware only
Doesn't it being a fn that takes context as an arg and possibly return a response make it a middleware? Like, what would the difference be between:
.on(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"], "*", (ctx) => {
return new Response();
})
.on(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"], "*", (ctx) => {
return new Response();
})
and
.use("*", (ctx) => {
return new Response();
})
.use("*", (ctx) => {
return new Response();
})
Seems like it would be the same?
Arjix
Arjix4w ago
there is a difference alright, you are not calling next ok, after testing locally, it looks like that makes no difference

Did you find this page helpful?