从0死磕全栈之Next.js 缓存与数据重新验证

在现代 Web 应用中,性能和数据新鲜度是两个关键指标。Next.js 提供了强大的缓存(Caching)与重新验证(Revalidation)机制,帮助开发者在提升性能的同时,确保用户获取到最新数据。本文将深入介绍 Next.js App Router 中的缓存策略及其使用方式。


1. 什么是缓存?

缓存是一种将计算结果(如 API 请求、数据库查询)临时存储起来的技术。当下次请求相同数据时,可以直接从缓存中读取,避免重复计算,从而显著提升响应速度和降低服务器负载。

在 Next.js 中,缓存不仅适用于数据请求,也适用于页面渲染结果。


2. fetch 的缓存与重新验证

默认行为

在 Next.js 的 App Router 中,fetch 请求默认不会被缓存 。但值得注意的是,即使 fetch 不缓存,Next.js 仍会对包含 fetch 的页面进行静态预渲染(Prerendering),并将整个 HTML 页面缓存下来。

强制缓存

你可以通过设置 cache: 'force-cache' 来显式启用缓存:

ts 复制代码
export default async function Page() {
  const data = await fetch('https://api.example.com/data', {
    cache: 'force-cache', // 启用缓存
  });
  return <div>{data.title}</div>;
}

该请求的结果将被缓存,并在后续请求中直接返回。

基于时间的重新验证(Time-based Revalidation)

为了让缓存数据保持"新鲜",Next.js 支持基于时间的重新验证:

ts 复制代码
export default async function Page() {
  const data = await fetch('https://api.example.com/data', {
    next: { revalidate: 3600 }, // 每小时重新验证一次
  });
}

这意味着:缓存最多保留 3600 秒(1 小时),之后下一次请求会触发重新获取数据,并更新缓存。


3. unstable_cache:缓存任意异步函数

除了 fetch,你可能还需要缓存数据库查询、复杂计算等操作。Next.js 提供了 unstable_cache API(注意:前缀 unstable_ 表示该 API 可能在未来变更)。

基本用法

ts 复制代码
import { unstable_cache } from 'next/cache';
import { getUserById } from '@/lib/data';

export default async function Page({ params }: { params: Promise<{ userId: string }> }) {
  const { userId } = await params;

  const getCachedUser = unstable_cache(
    async () => {
      return getUserById(userId);
    },
    [userId] // 缓存键:确保不同用户的数据独立缓存
  );

  const user = await getCachedUser();
  return <div>{user.name}</div>;
}

配置重新验证与标签

你可以通过第三个参数配置缓存策略:

ts 复制代码
const getCachedUser = unstable_cache(
  async () => getUserById(userId),
  [userId],
  {
    tags: ['user'],      // 用于后续按标签清除缓存
    revalidate: 3600,    // 1 小时后重新验证
  }
);

4. 按标签重新验证:revalidateTag

当你更新了用户数据,希望清除相关缓存时,可以使用 revalidateTag

步骤一:为缓存打标签

无论是 fetch 还是 unstable_cache,都可以添加 tags

ts 复制代码
// 使用 fetch 打标签
await fetch('https://api.example.com/user', {
  next: { tags: ['user'] }
});

// 或使用 unstable_cache 打标签
const getUser = unstable_cache(
  async (id) => db.user.find(id),
  ['user'],
  { tags: ['user'] }
);

步骤二:在更新操作中触发重新验证

通常在 Route HandlerServer Action 中调用:

ts 复制代码
import { revalidateTag } from 'next/cache';

export async function updateUser(id: string, data: any) {
  await db.user.update(id, data);
  revalidateTag('user'); // 清除所有带 'user' 标签的缓存
}

✅ 优势:一个标签可关联多个缓存项,实现批量失效。


5. 按路径重新验证:revalidatePath

如果你只想重新验证某个页面(及其数据),可以使用 revalidatePath

ts 复制代码
import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) {
  await savePost(formData);
  revalidatePath('/blog'); // 重新生成 /blog 页面
}

这会触发 Next.js 重新预渲染指定路径,并更新其缓存的 HTML 和数据。


6. 缓存策略对比

方法 适用场景 是否支持 revalidate 是否支持标签 是否适用于非 fetch
fetch + cache API 请求缓存 ✅(next.revalidate ✅(next.tags
unstable_cache 数据库查询、自定义函数缓存
revalidateTag 按标签批量清除缓存 --- ---
revalidatePath 重新生成特定页面 --- ---

7. 最佳实践

  • 优先使用 fetch 缓存 :对于外部 API,直接使用 fetch 的缓存选项最简单高效。
  • 敏感数据避免缓存 :如用户个人资料、支付信息等,应设为动态请求(cache: 'no-store')。
  • 合理设置 revalidate 时间:高频更新的数据设短时间(如 60 秒),静态内容可设更长。
  • 善用标签管理缓存 :通过 tags 实现精准、高效的缓存失效。
  • 结合 Server Actions 使用 :在用户操作(如提交表单)后立即触发 revalidateTagrevalidatePath,实现"即时更新"。

结语

Next.js 的缓存系统兼顾了性能灵活性 ,通过 fetchunstable_cacherevalidateTagrevalidatePath 等 API,开发者可以构建既快速又实时的应用。掌握这些机制,是构建高性能 Next.js 应用的关键一步。

相关推荐
JarvanMo6 小时前
8 个你可能忽略了的 Flutter 小部件(一)
前端
JarvanMo6 小时前
Flutter 中的微服务架构:拆解你的应用
前端
JarvanMo6 小时前
对我来说,那个框架就是 Flutter。
前端
Mintopia6 小时前
🧠 自监督学习在 WebAIGC 中的技术突破与应用前景
前端·人工智能·aigc
Mintopia6 小时前
🧭 传统 Web 开发最好的 AI 助手框架排行榜(2025版)
前端·人工智能·aigc
坚持就完事了6 小时前
003-HTML之表单
服务器·前端·html
晓得迷路了6 小时前
栗子前端技术周刊第 105 期 - npm 安全性加强、Storybook 10、htmx 4.0 Alpha 1...
前端·javascript·npm
七号练习生.c7 小时前
CSS入门
前端·css·tensorflow
程序员爱钓鱼7 小时前
Python编程实战——Python实用工具与库:Matplotlib数据可视化
前端·后端·python