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

Next.js客户端API请求使用memory-cache缓存失效问题

问题原因

你客户端用memory-cache缓存失效的核心原因是:它是内存级缓存,浏览器刷新页面后JS上下文会完全重置,内存里的缓存数据会被清空,所以每次刷新都得重新请求API。

可行解决方案

方案1:用浏览器本地存储(localStorage/sessionStorage)替代内存缓存

这是最直接的改造方案,把缓存数据存在客户端本地,刷新页面也不会丢失,需要自己实现过期逻辑(因为本地存储没有自动过期机制):

修改客户端请求代码:

const [results, setResults] = useState([]);

async function getData() {
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  // 用带时区的key区分不同用户的缓存,避免互相干扰
  const cacheKey = `${JSON.stringify(urls)}_${timezone}`;
  const cachedStr = localStorage.getItem(cacheKey);
  
  if (cachedStr) {
    const cachedData = JSON.parse(cachedStr);
    // 检查缓存是否在24小时有效期内
    if (Date.now() - cachedData.timestamp < 24 * 60 * 60 * 1000) {
      setResults(cachedData.data);
      return;
    }
    // 过期则删除旧缓存
    localStorage.removeItem(cacheKey);
  }

  // 无有效缓存时请求API
  const data = await Promise.all(urls.map(url => 
    fetch(`${url}&timezone=${timezone}`, options).then(resp => resp.json())
  ));
  
  // 存储缓存,带上时间戳用于后续过期判断
  localStorage.setItem(cacheKey, JSON.stringify({
    data,
    timestamp: Date.now()
  }));
  
  setResults(data);
}

useEffect(() => {
  getData();
}, []);

注意事项:

  • 缓存key必须包含时区,避免不同时区用户的缓存冲突
  • 本地存储只能存字符串,所以要通过JSON.stringify/JSON.parse序列化/反序列化数据
  • 手动判断过期时间,超过24小时则触发新请求

方案2:用Service Worker实现HTTP缓存(推荐长期缓存场景)

如果API响应允许缓存,可以用Service Worker拦截请求,实现stale-while-revalidate这类缓存策略——既让用户快速拿到缓存数据,后台又能悄悄更新缓存。Next.js可以通过next-pwa插件快速配置Workbox,简化Service Worker开发:

  1. 安装next-pwa依赖
  2. 在next.config.js中配置Workbox规则,指定API请求的缓存过期时间为24小时
  3. 配置完成后,客户端请求API时会自动复用缓存,过期后后台自动更新

方案3:回到服务端渲染,解决时区获取问题

如果不想在客户端处理缓存,也可以改用getServerSideProps,尝试从请求头获取用户时区:

export async function getServerSideProps(req) {
  // 从请求头获取时区(部分浏览器会发送Accept-Timezone),默认用UTC
  const timezone = req.headers['accept-timezone'] || 'UTC';
  const cacheKey = `${JSON.stringify(urls)}_${timezone}`;
  
  const value = cache.get(cacheKey);
  if (value) {
    return { props: { result: value } };
  }
  
  const data = await Promise.all(urls.map(url => 
    fetch(`${url}&timezone=${timezone}`, options).then(resp => resp.json())
  ));
  cache.put(cacheKey, data, 24 * 60 * 60 * 1000);
  
  return { props: { result: data } };
}

注意:Accept-Timezone并非所有浏览器都支持,兼容性有限。如果要覆盖所有场景,可以先让客户端加载时把时区通过接口传给服务端,再渲染页面,但会多一次请求开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:55:14