unjs / nitro

Next Generation Server Toolkit. Create web servers with everything you need and deploy them wherever you prefer.
https://nitro.unjs.io
MIT License
6.13k stars 503 forks source link

Caching fails when returning a Buffer (PNG image) #1894

Open jschroeter opened 11 months ago

jschroeter commented 11 months ago

Environment

Node: 18.18 Nitro: latest

Reproduction

  1. open Stackblitz
  2. open dev tools and disable cache in network tab
  3. click the reload button in the preview multiple times

Expected: 2 logos should be visible

Actual result: the second logo using the cached route breaks when reloading in between 5s (since the cache max age is set to 5s)

Describe the bug

Use case

I do want to return a dynamically generated PNG image in a Nitro route. This works fine in general.

Issue

I also would like to add caching using cachedEventHandler. But all requests that should return a cached response, return the serialised JSON instead of the binary data, e.g. {"type": "Buffer", "data": [137,80,78,71,13,10,26,10,0,...

Additional context

I guess it's related to https://github.com/unjs/unstorage/issues/142 and the Nitro Cache should use setItemRaw()/getItemRaw() for the case of a Buffer?

Logs

No response

bernhardberger commented 10 months ago

I can confirm this issue. It breaks SWR when using sharp on a node server. Interestingly though this issue isn't present when using ISR (which supposedly as per docs is the same as SWR with just some cache headers added for Netlify and Vercel?!)

jryd commented 8 months ago

We're experiencing this now also after swapping defineEventHandler for defineCachedEventHandler.

We run an API endpoint in Nuxt that proxies image requests to a protected/private source. We want to cache the response, but after using this we sporadically see the serialised JSON returned instead.

alexMugen commented 6 months ago

Any updates forthcoming?

alexMugen commented 6 months ago

Any updates ?

f-lawe commented 6 months ago

Experiencing the same issue here too. Is there a way to wrap up the response of defineCachedEventHandler so we can eventually process the serialized JSON into binary data when it occurs? The overall response won't be fully cached, but at least the proxied image will be.

f-lawe commented 6 months ago

So, we implemented the workaround I mentioned earlier: we have a regular defineEventHandler endpoint that calls our image cached using defineCachedEventHandler and converts the serialized JSON back to a buffer. The overall response is not cached by the browser, however we reduced our response time and made it flat (we used to have huge variations, depending on server load),

That's not ideal, but that's an improvement, and it works!

bernhardberger commented 3 months ago

So, we implemented the workaround I mentioned earlier: we have a regular defineEventHandler endpoint that calls our image cached using defineCachedEventHandler and converts the serialized JSON back to a buffer. The overall response is not cached by the browser, however we reduced our response time and made it flat (we used to have huge variations, depending on server load),

That's not ideal, but that's an improvement, and it works!

Is there any chance you could post a working implementation? I think this could help a lot of people since this issue isn't getting much attention..

Barbapapazes commented 3 weeks ago

Hey,

Here the code for the workaround

const buffer = defineCachedFunction(async () => {
  return Buffer.from("Hello, World!");
});

export default defineEventHandler(async (event) => {
  return Buffer.from(await buffer());
});