← 返回渲染测试

增量静态再生成 (ISR)

🔁 什么是 ISR?

ISR(Incremental Static Regeneration)是 Next.js 的一个强大特性, 它结合了静态生成的性能动态渲染的新鲜度

工作原理:

  1. 构建时:生成静态页面(和 SSG 一样)
  2. 首次访问:返回缓存的静态页面(快速)
  3. revalidate 时间后:下一个请求触发后台重新生成
  4. 生成期间:继续返回旧页面(不会阻塞用户)
  5. 生成完成后:新页面替换旧页面

💡 关键概念:stale-while-revalidate

ISR 使用了 stale-while-revalidate 策略:

1️⃣

Stale(陈旧)

返回缓存的页面(即使可能过期)→ 用户看到页面很快

2️⃣

While(同时)

在后台重新生成页面 → 不阻塞用户请求

3️⃣

Revalidate(重新验证)

生成完成后更新缓存 → 下一个用户看到新内容

📊 ISR 数据

标题:

ISR 测试页面

描述:

这个页面每 30 秒会重新生成一次

渲染时间:

2025-12-27T07:41:47.588Z

✅ 在 30 秒内保持不变,之后会更新

随机值:

217

✅ 每次重新验证时都会变化

重新验证间隔:

30

✅ export const revalidate = 30;

🧪 如何验证 ISR?

  1. 查看构建输出:
    pnpm build

    在构建日志中,这个页面会显示为:
    ○ /rendering-test/isr (30 seconds)
    ○ 表示静态生成,括号中是 revalidate 时间

  2. 测试重新验证:

    1. 记录当前渲染时间
    2. 在 30 秒内刷新多次 → 时间不变(使用缓存)
    3. 等待 30 秒后刷新 → 仍返回旧页面(stale)
    4. 再次刷新 → 看到新时间(revalidate 完成)

  3. 查看终端日志:

    在构建时和重新验证时,会打印 [ISR] 日志
    注意:不是每次访问都打印,只在重新生成时打印

  4. 检查 Response Headers:

    打开 Network 面板,查看响应头:
    Cache-Control: s-maxage=30, stale-while-revalidate

⏱️ ISR 时间轴示例

00:00 - 构建完成,生成静态页面(时间戳:A)
00:05 - 用户 1 访问 → 返回页面 A(快速)
00:15 - 用户 2 访问 → 返回页面 A(仍在 30 秒内)
00:35 - 用户 3 访问 → 返回页面 A + 触发后台重新生成
00:36 - 后台生成完成(时间戳:B)
00:40 - 用户 4 访问 → 返回页面 B(新内容)✅

⚠️ 注意:用户 3 看到的是旧页面(A),因为新页面(B)还在生成中。 这确保了用户始终能快速获得响应。

💡 适用场景

✅ 最适合

  • 博客文章(定期发布)
  • 电商产品页(价格、库存更新)
  • 新闻网站(定时更新)
  • 文档站点(内容更新)
  • API 数据展示(定期同步)

❌ 不适合

  • 用户个性化内容(每人不同)
  • 秒级实时数据(股票 tick)
  • 用户输入后的即时反馈
  • 需要认证的页面
  • 完全静态的内容(用 SSG 更好)

💻 代码示例

// app/blog/[slug]/page.tsx

// 配置 ISR:每 60 秒重新验证
export const revalidate = 60;

export default async function BlogPost({ params }) {
  // 这个数据获取在构建时和重新验证时执行
  const post = await fetchPost(params.slug);
  
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
      <time>{post.updatedAt}</time>
    </article>
  );
}

// 动态路由需要 generateStaticParams
export async function generateStaticParams() {
  const posts = await fetchAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

// 或者使用 fetch 的 revalidate 选项
async function fetchPost(slug) {
  const res = await fetch(`https://api.example.com/posts/${slug}`, {
    next: { revalidate: 60 }, // 60 秒后重新验证
  });
  return res.json();
}

⚙️ ISR 配置选项

1️⃣ 页面级 revalidate

export const revalidate = 60; // 秒

页面中的所有 fetch 都使用这个 revalidate 时间

2️⃣ fetch 级 revalidate

fetch(url, { next: { revalidate: 30 } })

单个 fetch 请求的 revalidate 时间

3️⃣ 路由段配置

export const revalidate = 60;
export const dynamic = 'force-static';

组合配置,确保静态生成 + ISR

⚖️ 优缺点

✅ 优点

  • 性能好:接近静态页面的速度
  • 内容新:定期自动更新内容
  • 无需重新构建:内容更新无需重新部署
  • 不阻塞用户:后台更新,用户无感知
  • 可缓存:可以通过 CDN 缓存
  • SEO 友好:静态 HTML,搜索引擎可索引

❌ 缺点

  • 延迟更新:内容更新有延迟(revalidate 时间)
  • 可能看到旧内容:重新验证期间返回旧页面
  • 服务器负载:定期重新生成需要服务器资源
  • 不适合实时:无法做到秒级更新
  • 不可个性化:所有用户看到相同内容