You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何SWR在Loader中用CDN缓存比浏览器缓存不阻塞页面加载?

Remix中Cache-Control在浏览器与CDN缓存的行为差异问题

初始loader与headers函数

export async function loader() {
  const expenses = [
    {
      id: '637f853a8517a37d05c402b5',
      title: 'first expense',
      amount: 234,
    },
  ];

  // 延迟loader执行以测试缓存效果
  await new Promise((res) => {
    setTimeout(res, 5000);
  });

  console.log('loader is being called');

  return json(expenses, {
    headers: {
      'Cache-Control': 'max-age=10, stale-while-revalidate=59',
    },
  });
}

export function headers({ loaderHeaders }) {
  return {
    'Cache-Control': loaderHeaders.get('Cache-Control'),
  };
}

使用max-age时,浏览器会正确缓存10秒,但重新验证阶段loader会被调用,页面因setTimeout阻塞5秒才加载。按预期此时应该能直接返回过期缓存(stale cache),同时后台异步重新验证,但实际页面需要等待loader执行完成,这和stale-while-revalidate的预期不符。

CDN缓存配置代码

改用s-maxage配置CDN缓存的代码如下:

return json(expenses, {
    headers: {
      'Cache-Control': 's-maxage=1, stale-while-revalidate=59',
    },
  });

部署在Vercel上时,stale-while-revalidate工作正常:CDN直接返回过期缓存让页面快速加载,后台异步完成重新验证,完全不受setTimeout的影响。为什么CDN缓存和浏览器缓存的行为会有这种差异?


期望效果

无论使用浏览器缓存还是CDN缓存,都应该返回过期缓存并在后台异步重新验证,页面可以立即(或通过CDN快速)加载。

当前现象

  • 使用max-age+stale-while-revalidate配置浏览器缓存时:max-age生效期间页面加载正常,但重新验证时loader里的setTimeout会阻塞页面加载,这和在loader中使用SWR的初衷相悖(除非我的理解有误)。
  • 使用s-maxage+stale-while-revalidate配置CDN缓存时:s-maxage生效期间页面加载快速,setTimeout不会阻塞页面——CDN返回过期缓存,页面快速加载,这正是我想要的SWR效果,但我希望浏览器缓存也能实现该效果,同时想明白loader不阻塞页面的原因。

已尝试操作

  • 在MacBook的不同浏览器及iPhone上测试,浏览器缓存的行为一致。
  • 尝试fly、Netlify、Vercel等部署平台,结果相同;本地npm run dev运行时也是同样现象。
  • 新建Remix项目测试,结果一致。

内容的提问来源于stack exchange,提问作者Michael Frieze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:35:16