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
5.85k stars 493 forks source link

Using `shouldBypassCache`, should it still return stale-while-revalidate headers? #2731

Open kaitoqueiroz opened 1 week ago

kaitoqueiroz commented 1 week ago

Discussed in https://github.com/unjs/nitro/discussions/2714

Originally posted by **kaitoqueiroz** September 5, 2024 # Environment: Operating System: Linux Node Version: v20.15.0 Nuxt Version: 3.13.0 Package Manager: pnpm@9.4.0 # Reproduction https://stackblitz.com/edit/nuxt-starter-kjhdkn?file=server%2Fapi%2Ftest.get.js ⚠️ Please be aware that the problem I'm describing can't be reproduced in the stackblitz preview feature, once it runs with ServiceWorker. The code should be downloaded and run locally: `npm install` then `npm run dev` # Context: I'm working on a feature that uses SWR to cache the API responses for a certain period and revalidate after the TTL. When I switch pages, I make a request to the API, and I want the cache to be bypassed when I set the `preview=true` query parameter. The problem is that the browser caches the response regardless, and when the user navigates, it still serves cached data. image Response headers in the first request (uncached): image Code: ```js export default defineCachedEventHandler( async (event) => { return new Date(); }, { // explicitly enable SWR swr: true, maxAge: 30, staleMaxAge: 60 * 60 * 24 * 7, // 1 week shouldBypassCache: (event) => { const { preview } = getQuery(event); return preview === 'true'; }, } ); ``` Is it possible to avoid the response being cached in the browser when the cache is bypassed? Using shouldBypassCache, should it still return stale-while-revalidate headers? Could anyone help me with that, please?
dencs08 commented 1 week ago

I'm also facing this problem, no idea how to work around it yet. It seems to me that shouldBypassCache should run every request regardless of other parameters because in it's current state it seems pointless as you cannot bypass cache using it. Same thing goes for shouldInvalidateCache() - runs only when the response wasn't cached yet which makes it unusable (at least i don't see the point of using it in this state).

I've even tried to manually invalidate the cache before the request with an endpoint setup like so:

export default defineEventHandler(async (event) => {
  const storage = useStorage("cache");
  try {
    const cacheKeys = await storage.getKeys("nitro:handlers");

    // Remove all cache items concurrently
    await Promise.all(cacheKeys.map((element) => storage.removeItem(element)));

    return { success: true };
  } catch (error: any) {
    console.error("Error invalidating cache:", error);
    throw createError({
      statusCode: error.statusCode || 500,
      statusMessage: error.message || "Failed to invalidate cache",
    });
  }
});

I've noticed it correctly removes the file from the cache folders in nitro but even after running it, my api endpoint still serves cached response.

dencs08 commented 1 week ago

@kaitoqueiroz I've opened a new issue with a workaround which might work for you, try it out and let me know if it worked.