spring的技术笔记
前端2 分钟阅读

App Router 数据获取:缓存、revalidate 与 Server Actions

把 Next.js App Router 里的 fetch 缓存、按需再验证和 Server Actions 放在同一张决策表里,避免「默认全缓存」踩坑。

在 App Router 里写数据层,最容易乱的不是语法,而是默认行为。fetch 是否缓存、页面是否静态、何时该用 Server Actions,决定了你线上看到的是「秒开的旧数据」还是「每次都打到源站」。

三种常见路径

  1. 服务端 fetch(RSC):适合读多写少、可接受短暂陈旧的内容。
  2. revalidate / 标签失效:适合「大体静态,偶尔更新」的列表与详情。
  3. Server Actions:适合表单提交、写操作,以及必须在服务端完成的副作用。
// 60 秒内复用结果;过期后下一次请求触发后台再生成
export default async function PostsPage() {
  const res = await fetch("https://api.example.com/posts", {
    next: { revalidate: 60, tags: ["posts"] },
  });
  const posts = await res.json();
  return <PostList posts={posts} />;
}

什么时候关掉缓存

用户私有数据、购物车、后台配置面板,通常应该:

await fetch(url, { cache: "no-store" });

或者在页面段配置 export const dynamic = "force-dynamic"。原则很简单:能被 CDN 共享的才缓存;带身份上下文的默认不缓存。

Server Actions 的边界

Server Actions 不是「前端调后端的万能 RPC」。它适合:

  • 表单写入、删除、状态变更
  • 需要密钥、只能放服务端的逻辑

不适合把所有读接口都改成 Action——读路径继续用 fetch / 数据库直查,语义更清晰,也更好做 HTTP 缓存。

实践建议

  • 先画数据所有权:公共 / 用户私有 / 运营可变。
  • 公共内容优先 ISR(revalidate),私有内容 no-store。
  • 写操作后用 revalidateTag / revalidatePath 主动失效,不要指望用户手动刷新。

小结

App Router 的数据获取没有银弹,只有匹配场景的默认值。把缓存策略写进代码评审清单,比记住某一个 API 名更重要。