跳转到内容

Next.js增量静态再生成(ISR)

来自代码酷

Next.js增量静态再生成(ISR)[编辑 | 编辑源代码]

增量静态再生成(Incremental Static Regeneration,简称ISR)是Next.js提供的一项强大功能,它允许开发者在构建静态页面后,按需或在特定时间间隔内重新生成页面,从而在不牺牲性能的情况下实现动态内容更新。ISR结合了静态生成(SSG)和服务器端渲染(SSR)的优点,适用于需要频繁更新内容但又不希望每次请求都重新渲染页面的场景。

介绍[编辑 | 编辑源代码]

ISR的核心思想是:在首次请求时生成静态页面,并在后续请求中按需或在设定的时间间隔内重新生成页面。这意味着:

  • 用户首次访问页面时,会看到预先生成的静态内容。
  • 当页面需要更新时,Next.js会在后台重新生成页面,而用户仍然可以看到旧版本,直到新版本生成完成。
  • 可以设置重新生成的频率(如每60秒),确保内容不会过于陈旧。

ISR特别适合以下场景:

  • 电子商务网站的产品列表页
  • 新闻网站的新闻详情页
  • 博客平台的文章页
  • 任何需要混合静态和动态内容的场景

工作原理[编辑 | 编辑源代码]

ISR的工作流程可以用以下mermaid图表示:

graph LR A[用户请求页面] --> B{页面是否存在?} B -->|是| C[返回缓存的静态页面] B -->|否| D[生成新页面并缓存] C --> E{是否超过revalidate时间?} E -->|否| F[继续使用缓存] E -->|是| G[在后台重新生成页面] G --> H[下次请求返回新页面]

数学上,ISR的重新生成条件可以表示为:

tcurrenttlastGeneratedtrevalidate

其中:

  • tcurrent 是当前时间
  • tlastGenerated 是页面最后生成时间
  • trevalidate 是设置的重新生成间隔

基本用法[编辑 | 编辑源代码]

要在Next.js中使用ISR,需要在`getStaticProps`函数中返回`revalidate`属性:

// pages/products/[id].js
export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/products/${params.id}`);
  const product = await res.json();

  return {
    props: {
      product,
    },
    // 每60秒重新生成页面
    revalidate: 60,
  };
}

同时,你还需要使用`getStaticPaths`来指定哪些路径应该预先生成:

export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/products');
  const products = await res.json();

  const paths = products.map((product) => ({
    params: { id: product.id.toString() },
  }));

  // 预生成前10个产品页面,其余按需生成
  return { paths: paths.slice(0, 10), fallback: 'blocking' };
}

关键参数说明:

  • `revalidate`: 重新生成页面的时间间隔(秒)
  • `fallback`:
 * `false`: 只生成`paths`中指定的页面,其他路径返回404
 * `true`: 未生成的页面首次访问时在客户端生成
 * `'blocking'`: 未生成的页面首次访问时在服务器端生成

高级用法[编辑 | 编辑源代码]

按需重新生成[编辑 | 编辑源代码]

Next.js 12.1+ 支持按需重新生成(On-demand ISR),可以通过API路由触发特定页面的重新生成:

// pages/api/revalidate.js
export default async function handler(req, res) {
  // 检查密钥(生产环境中应使用更安全的验证方式)
  if (req.query.secret !== process.env.REVALIDATE_SECRET) {
    return res.status(401).json({ message: 'Invalid token' });
  }

  try {
    // 重新生成指定路径的页面
    await res.revalidate(req.query.path);
    return res.json({ revalidated: true });
  } catch (err) {
    return res.status(500).send('Error revalidating');
  }
}

然后可以通过发送请求到`/api/revalidate?path=/products/1&secret=...`来手动触发重新生成。

动态重新生成时间[编辑 | 编辑源代码]

你可以根据内容动态设置`revalidate`时间:

export async function getStaticProps() {
  const data = await getData();
  
  // 根据数据重要性设置不同的重新生成时间
  const revalidate = data.isImportant ? 10 : 3600;
  
  return {
    props: { data },
    revalidate,
  };
}

实际案例[编辑 | 编辑源代码]

案例1:电子商务产品页[编辑 | 编辑源代码]

假设你有一个电子商务网站,产品信息每天更新几次,但不会每分钟都变化。使用ISR可以:

1. 预生成热门产品页面 2. 设置`revalidate: 3600`(1小时) 3. 当产品价格变化时,通过按需重新生成API立即更新特定页面

案例2:新闻网站[编辑 | 编辑源代码]

对于新闻网站:

  • 首页:`revalidate: 60`(每分钟检查新文章)
  • 新闻详情页:`revalidate: 3600`(每小时检查更新)
  • 突发新闻:使用按需重新生成立即更新

性能考虑[编辑 | 编辑源代码]

使用ISR时需要注意:

  • 重新生成过程会增加服务器负载,特别是在流量大的网站上
  • 太短的`revalidate`时间可能使ISR失去意义(考虑使用SSR)
  • 对于几乎不变化的页面,使用较长的`revalidate`或纯SSG
  • 对于频繁变化的页面,考虑使用SSR或按需重新生成

最佳实践[编辑 | 编辑源代码]

1. 合理设置revalidate时间:根据内容更新频率设置,热门内容可以设置较短时间 2. 使用fallback: 'blocking:提供更好的用户体验,避免布局偏移 3. 结合按需重新生成:对于关键内容更新,不要完全依赖定时重新生成 4. 监控重新生成性能:确保重新生成过程不会影响用户体验 5. 错误处理:在重新生成失败时应有备用方案

限制[编辑 | 编辑源代码]

ISR虽然强大,但也有一些限制:

  • 不适用于需要实时更新的场景(如聊天应用)
  • 重新生成期间用户可能看到旧内容
  • Vercel以外的部署环境可能需要额外配置
  • 大量页面可能导致存储问题

总结[编辑 | 编辑源代码]

Next.js的增量静态再生成(ISR)提供了一种灵活的方式来构建高性能、动态的网站。它通过在静态生成和服务器端渲染之间取得平衡,为开发者提供了更多的选择。通过合理使用定时重新生成和按需重新生成,可以构建出既快速又新鲜的Web应用。

对于大多数内容驱动的网站,ISR应该是首选的渲染策略,它提供了最佳的性价比:良好的性能、较低的服务成本以及新鲜的内容。