6月2日 23:15

Next.js SSR、SSG 和 ISR 有什么区别?怎么选?

SSR、SSG、ISR 是三种不同的页面渲染策略,区别在于 HTML 什么时候生成。选哪个取决于数据的更新频率和页面的实时性要求。

三种策略对比

策略HTML 生成时机适合场景性能
SSG构建时博客、文档、营销页最快(CDN 缓存)
SSR每次请求时仪表盘、个人主页中等(服务端计算)
ISR构建时 + 定时更新商品列表、新闻接近 SSG 的速度

SSG(Static Site Generation)

构建时生成 HTML,部署后不变化。速度最快——CDN 直接返回静态文件,零服务端计算。

tsx
// App Router 默认就是 SSG // 没有 dynamic 数据获取的页面自动静态生成 export default function AboutPage() { return <h1>关于我们</h1>; } // 带数据的 SSG:构建时获取 async function BlogList() { const posts = await db.post.findMany(); // 构建时执行 return posts.map(p => <article key={p.id}>{p.title}</article>); }

局限:数据变化后需要重新构建部署。适合不常变的内容。

SSR(Server-Side Rendering)

每次请求时生成 HTML。数据始终最新,但每次请求都有服务端计算开销。

tsx
// App Router: 使用动态数据获取自动触发 SSR async function Dashboard() { const stats = await fetch('https://api.example.com/stats', { cache: 'no-store' // 不缓存,每次请求重新获取 }).then(r => r.json()); return <div>{stats.users} 用户</div>; }

cache: 'no-store' 告诉 Next.js 这个请求不能缓存,必须每次执行。适合实时数据。

ISR(Incremental Static Regeneration)

SSG 的升级版——静态生成 HTML,但后台定时重新生成。兼具 SSG 的速度和数据的新鲜度。

tsx
async function ProductList() { const products = await fetch('https://api.example.com/products', { next: { revalidate: 3600 } // 每 3600 秒(1 小时)重新验证 }).then(r => r.json()); return products.map(p => <div key={p.id}>{p.name}</div>); }

ISR 的工作流程:

  1. 第一个用户请求 → 返回缓存的静态 HTML(快)
  2. 后台检查 revalidate 时间是否到期
  3. 到期后重新生成 HTML,替换旧缓存
  4. 下一个用户请求 → 返回新生成的 HTML

关键点:用户永远看到的是缓存的页面(快),后台异步更新。最坏情况数据延迟 revalidate 秒。

怎么选

选 SSG:内容几乎不变(文档、博客、营销页)

选 ISR:内容定期更新(商品列表、新闻、排行榜),能接受短暂延迟

选 SSR:内容必须实时(仪表盘、用户个人页、搜索结果)

常见错误:所有页面都用 SSR。大部分页面用 ISR 就够了——1-5 分钟的数据延迟用户感知不到,但性能提升显著。

App Router 中的 revalidate 策略

tsx
// 定时重新验证(ISR) fetch(url, { next: { revalidate: 60 } }); // 60 秒 // 按需重新验证:修改数据后手动触发 import { revalidateTag, revalidatePath } from 'next/cache'; // 在 Server Action 里触发 async function updateProduct(formData: FormData) { await db.product.update({ ... }); revalidateTag('products'); // 刷新所有 products 标记的缓存 revalidatePath('/products'); // 刷新 /products 页面 }

按需重新验证(On-Demand Revalidation)比定时更精准——数据变了立即刷新,没变就不浪费资源。

标签:Next.js