切换语言
切换主题

Next.js SSR vs SSG vs ISR:渲染策略选择指南

“为什么首页加载要3秒?“老板盯着屏幕,我盯着Chrome DevTools的瀑布图——红色的TTFB长得像条蛇。那是我第一次意识到,可能一开始就选错了渲染策略。

这不是个案。在Next.js的GitHub Issues里,每天都有人问:“我该用SSR还是SSG?""ISR配置了为啥不生效?“说实话,我之前也一头雾水。明明文档都看了,遇到具体项目还是不知道该选哪个。

你可能也遇到过类似的困惑:

  • 用了SSR,结果首屏加载慢得让人抓狂
  • 选了SSG,每次更新内容都要重新构建整个站点
  • ISR看起来很美好,配置完却发现根本不生效

其实这三种渲染策略没有”最好”的,只有”最合适”的。今天我们就来彻底搞清楚,什么场景该用哪种策略,以及怎么避开常见的坑。

40-60%
SSG 比 SSR 快
AWS 数据
50ms
SSG TTFB
Vercel 官方数据
200-500ms
SSR TTFB
Vercel 官方数据
2.3s→0.8s
ISR 性能提升
某电商网站实测
数据来源: AWS、Vercel 官方数据及实战案例

先搞清楚:三种渲染策略到底是什么

在讨论怎么选之前,咱们先把这三个概念搞清楚。我试着用最直白的方式来讲。

SSG(静态站点生成):提前做好的便当

想象你开了个便当店,每天早上提前做好100份便当放在柜台,客人来了直接拿就走。这就是SSG的工作方式。

具体来说:

  • 什么时候生成:在你执行next build的时候,Next.js就把所有页面的HTML都生成好了
  • 用户访问时:CDN直接返回提前生成的HTML文件,超快
  • 什么时候适合:内容不常变的页面,比如企业官网、产品介绍页、博客文章

优势明显

  • 速度快到飞起。根据AWS的数据,SSG页面加载速度比SSR快40-60%
  • TTFB(首字节时间)通常在50ms以内,Vercel官方测过
  • 服务器压力几乎为0,流量再大也不怕
  • 成本低,静态文件托管便宜得多

但也有限制

  • 内容更新了?不好意思,得重新构建整个站点
  • 页面多了构建时间会很长,几千个页面可能要等半小时
  • 不支持个性化内容,所有用户看到的都一样

说白了,SSG就是用”提前准备”换来的速度。

SSR(服务端渲染):现炒现卖

还是便当店的例子,但这次你不提前做便当了。客人点什么,你现场炒什么。这就是SSR。

具体来说:

  • 什么时候生成:每次用户请求时,服务器实时生成HTML
  • 用户访问时:等服务器查数据库、调API、渲染HTML,然后返回
  • 什么时候适合:内容实时变化或需要个性化的页面

优势在这

  • 内容永远是最新的,用户看到的是此时此刻的数据
  • 支持个性化,可以根据用户的Cookie、权限展示不同内容
  • 可以访问请求时才有的信息,比如请求头、查询参数

但代价不小

  • 慢。TTFB通常在200-500ms,Vercel官方数据
  • 服务器压力大,流量一上来服务器可能扛不住
  • 成本高,需要一直跑着服务器

有个真实案例:某电商网站用SSR,首屏加载要2.3秒。后来改成ISR,直接降到0.8秒。

ISR(增量静态再生):便当+现炒的混合模式

这次你聪明了:提前做好便当,但每隔一段时间(比如每小时)更新一次。客人大部分时候拿到的是提前做好的,但内容又不会太旧。这就是ISR。

具体来说:

  • 初次构建next build时生成静态HTML(像SSG)
  • 后续更新:根据你设置的revalidate时间,后台自动重新生成页面
  • 用户访问时:大部分时候返回缓存的HTML(快),过期了就后台更新

这是个平衡点

  • 有SSG的速度(用户拿到的是静态文件)
  • 又有SSR的新鲜度(内容会定期更新)
  • 不需要每次都重新构建整个站点

配置很简单(App Router语法):

// app/posts/[id]/page.tsx
export const revalidate = 60; // 60秒后重新验证

export default async function Post({ params }) {
  const post = await getPost(params.id);
  return <div>{post.content}</div>;
}

但有些坑

  • 配置了不生效?可能是你在开发环境(next dev)测试,ISR只在生产环境(next build + next start)才工作
  • 部署平台不支持?Vercel原生支持,其他平台可能需要额外配置

说实话,ISR是我现在最常用的策略。它解决了SSG和SSR各自的痛点,真的很香。

决策树:什么场景用什么策略

好了,概念搞清楚了。现在最关键的问题来了:我的项目该用哪个?

别慌,我给你整理了一个决策流程。你可以对照自己的项目,一步步往下走。

第一步:问自己三个问题

问题1:内容需要个性化吗?

如果你的页面需要根据用户的身份、权限、偏好展示不同内容,那直接用SSR

典型场景:

  • 用户仪表盘(每个人看到的数据不一样)
  • 个人资料页
  • 购物车页面
  • 任何需要认证后才能访问的页面

为啥?个性化内容没法提前生成,只能在用户请求时动态生成。

问题2:内容多久更新一次?

这个问题决定了你用SSG还是ISR。

  • 几秒到几分钟更新一次:用SSR

    • 比如股票行情、体育赛事比分、聊天消息
    • 这种实时性要求高的,SSR是唯一选择
  • 几分钟到几小时更新一次:用ISR

    • 比如新闻网站、博客首页、产品列表、电商库存
    • ISR可以设置revalidate: 300(5分钟),既快又新鲜
  • 很少更新,或者手动触发更新:用SSG

    • 比如企业官网、产品介绍页、帮助文档
    • 这些内容可能几周甚至几个月才改一次

问题3:流量有多大?

流量大小会影响成本和性能考量。

  • 超高流量(每天百万级PV):优先SSGISR

    • 静态文件可以直接走CDN,成本低性能好
    • 如果用SSR,服务器压力会很大,成本飙升
  • 中低流量:三种都可以

    • 如果内容实时性要求高,SSR也完全能接受
    • 但既然能用ISR,为啥不用呢?

第二步:常见场景速查表

我把一些典型场景整理了出来,你可以直接对号入座:

用SSG的场景

  • ✅ 企业官网
  • ✅ 产品介绍页、定价页
  • ✅ 营销落地页
  • ✅ 博客文章详情页(内容发布后不再修改)
  • ✅ 技术文档、API文档
  • ✅ 帮助中心、FAQ

记住一个关键词:静态、公共、不常更新

用SSR的场景

  • ✅ 社交媒体信息流(Facebook、Twitter式)
  • ✅ 用户个人仪表盘
  • ✅ 购物车、订单页面
  • ✅ 实时数据面板
  • ✅ 搜索结果页(根据查询参数生成)
  • ✅ 需要认证的页面(基于Cookie判断)

记住一个关键词:动态、个性化、实时

用ISR的场景(我的最爱):

  • ✅ 博客首页、文章列表(定期有新文章)
  • ✅ 新闻网站
  • ✅ 电商产品详情页(价格、库存定期更新)
  • ✅ 论坛帖子页(评论、点赞数延迟几分钟更新可以接受)
  • ✅ UGC内容平台(内容更新频繁但不需要秒级实时)
  • ✅ 天气预报、汇率信息

记住一个关键词:定期更新、可接受延迟、高流量

第三步:混合使用才是王道

有个误区要打破:你不用全站只用一种策略。

实际上,大部分项目都是混合使用的:

  • 首页和产品列表用ISR(流量大,内容定期更新)
  • 产品详情页用SSG(内容稳定)或ISR(价格库存会变)
  • 用户仪表盘用SSR(个性化)
  • 关于我们、联系我们用SSG(完全静态)

我们团队的一个电商项目就是这么做的:

  • 首页(ISR,10分钟更新)
  • 商品列表(ISR,5分钟更新)
  • 商品详情(ISR,3分钟更新,因为库存会变)
  • 购物车(SSR,必须实时)
  • 用户中心(SSR,个性化)
  • 关于我们、隐私政策(SSG,几乎不变)

这样搭配下来,性能和实时性都兼顾到了。

一句话决策口诀

如果你还是拿不准,记住这个:

静态用SSG,实时用SSR,定期更新用ISR

当你不确定时,先用ISR试试。它是三者中最平衡的选择,出错概率最低。

三大常见坑和解决方案

讲完理论,咱们聊点实际的。这三个坑,我都踩过,估计你也会遇到。

坑1:ISR的revalidate不生效

症状:你兴冲冲地配置了revalidate: 60,以为页面会每分钟更新,结果等了半天,内容还是老样子。

我当时的崩溃:真的,我第一次用ISR时在这里卡了整整两天。查了无数文档,改了N次配置,就是不work。

原因有三个

  1. 开发环境不支持ISR

    这是最常见的原因。next dev开发模式下,ISR根本不工作!它只在生产模式下才生效。

    解决办法

    # 不要用 next dev 测试ISR
    # 必须先构建再启动
    npm run build
    npm run start
    
    # 然后访问页面测试
  2. 部署平台不支持

    不是所有平台都原生支持ISR。Vercel支持得很好(毕竟是Next.js官方),但其他平台可能需要额外配置。

    比如Netlify:需要安装@netlify/plugin-nextjs插件才能支持ISR。

    检查方法:去你的部署平台文档搜”Next.js ISR support”。

  3. CDN缓存覆盖了ISR

    如果你在Next.js前面加了一层CDN或反向代理(如Cloudflare),它们可能缓存了整个响应,导致ISR的更新机制失效。

    解决办法:配置CDN,让它尊重Cache-Control头,或者针对ISR页面设置较短的CDN缓存时间。

我的建议:配置ISR后,一定要在生产环境测试。可以用console.log(new Date())打印页面生成时间,来验证revalidate是否生效。

坑2:SSR首屏加载慢到怀疑人生

症状:用了SSR后,首屏白屏时间长达2-3秒,用户都快跑了。

真实案例:我们有个项目,首页用了SSR去获取用户信息和推荐内容。结果首屏TTFB直接1.2秒,加上渲染时间,用户要等3秒才能看到内容。老板看了直摇头。

原因分析

SSR慢,通常是因为服务器端数据获取慢。可能是:

  • API调用慢(外部API延迟高)
  • 数据库查询慢(没索引、查询复杂)
  • 串行请求(一个接口等另一个接口)
  • 服务器性能差或地理位置远

解决方案有四个

  1. 用Streaming SSR和Suspense(React 18+)

    不要等所有数据都拿到再渲染,可以先返回页面框架,数据到了再流式传输。

    // app/dashboard/page.tsx
    import { Suspense } from 'react';
    
    export default function Dashboard() {
      return (
        <div>
          <h1>用户仪表盘</h1>
          {/* 快速渲染的部分 */}
          <UserInfo />
    
          {/* 慢速数据用Suspense包裹 */}
          <Suspense fallback={<div>加载统计数据...</div>}>
            <SlowStats />
          </Suspense>
        </div>
      );
    }

    这样用户能更快看到页面,体验好很多。

  2. 并行请求数据

    把多个API调用改成并行执行:

    // ❌ 串行:慢
    const user = await getUser();
    const posts = await getPosts(user.id);
    
    // ✅ 并行:快
    const [user, posts] = await Promise.all([
      getUser(),
      getPosts()
    ]);
  3. 考虑改用ISR

    很多时候你以为需要SSR,但其实ISR就够了。

    问问自己:这个页面的数据真的需要实时吗?如果延迟1分钟更新可以接受,那就用ISR。

    我们那个首页后来改成了ISR(revalidate: 60),首屏加载直接从3秒降到0.7秒。

  4. 部署到Edge

    如果你在用Vercel,可以试试Edge Functions。它会把你的SSR函数部署到全球CDN节点,离用户更近,延迟更低。

    // app/api/data/route.ts
    export const runtime = 'edge'; // 就这一行

坑3:SSG构建时间太长

症状:网站有几千个页面,每次next build要等20-30分钟,甚至超时失败。

痛点场景:电商网站有5000个商品,博客有3000篇文章,用SSG的话构建时要为每个页面生成HTML。

为啥会慢

SSG在构建时生成所有页面的HTML。页面越多,构建时间越长。而且很多页面可能根本没人访问(长尾商品、老文章)。

解决方案

  1. 用fallback策略

    不要一次性生成所有页面,只生成热门页面,其他页面按需生成。

    // app/posts/[id]/page.tsx
    export async function generateStaticParams() {
      // 只返回热门的100篇文章
      const posts = await getTopPosts(100);
      return posts.map(post => ({ id: post.id }));
    }
    
    // 其他页面第一次访问时生成
    export const dynamicParams = true;
  2. 结合ISR

    构建时只生成首页和热门页面,其他页面用ISR按需生成。

    这样构建时间大大缩短,用户访问时也不会慢(因为有缓存)。

  3. 增量构建(Incremental Builds)

    Vercel支持增量构建,只重新构建变化的页面。如果你更新了一篇文章,不需要重新构建整个站点。

    其他平台可能需要自己实现这个逻辑。

实际效果

我们的一个博客项目有2000篇文章。最开始用纯SSG,构建要15分钟。后来改成:

  • 构建时只生成最新的50篇
  • 其他文章用dynamicParams = true按需生成
  • 所有文章页用ISR(revalidate: 3600

现在构建时间降到2分钟,用户访问速度也没变慢。

Next.js 15的新特性:React Server Components和PPR

聊到这,顺便提一下Next.js 15带来的两个新东西。虽然它们不完全是”渲染策略”,但确实影响了我们怎么构建页面。

React Server Components(RSC):组件级的SSR

如果你用过Next.js 13+的App Router,你已经在用Server Components了。

它和传统SSR有啥区别?

  • 传统SSR:整个页面在服务器端渲染
  • RSC:默认情况下,组件在服务器端渲染,只有需要交互的组件才在客户端运行

好处很明显

  1. JS bundle变小了

    Server Component的代码不会被打包到客户端。Next.js官方数据显示,用了RSC后,客户端JavaScript体积能减少30-50%。

    页面加载更快,用户手机也不那么烫了。

  2. 直接访问后端资源

    Server Component可以直接查数据库、读文件系统,不需要建API端点。

    // app/posts/page.tsx
    // 这是个Server Component,可以直接查数据库
    async function getPosts() {
      const posts = await db.posts.findMany();
      return posts;
    }
    
    export default async function PostsPage() {
      const posts = await getPosts();
      return (
        <div>
          {posts.map(post => (
            <PostCard key={post.id} post={post} />
          ))}
        </div>
      );
    }

实战建议

  • 默认用Server Component(App Router下就是默认的)
  • 只在需要交互的地方用Client Component(加'use client'
  • 数据获取和静态UI用Server Component,按钮、表单、动画用Client Component

这样一来,你的应用既有SSR的SEO优势,又有很小的JS bundle。

Partial Prerendering(PPR):静态+动态的混合体

PPR是Next.js 15引入的实验性功能,让你在同一个页面里混用静态和动态部分。

举个例子

电商产品页:

  • 产品描述、图片(静态,构建时生成)
  • 库存、价格(动态,请求时获取)

用PPR的话,静态部分在构建时就生成好了,动态部分每次请求时才计算。这样既快又新鲜。

怎么用

// next.config.js
module.exports = {
  experimental: {
    ppr: true,
  },
};

// app/products/[id]/page.tsx
export const experimental_ppr = true;

export default function ProductPage({ params }) {
  return (
    <div>
      {/* 静态部分:构建时生成 */}
      <ProductDescription id={params.id} />

      {/* 动态部分:请求时生成 */}
      <Suspense fallback={<div>加载中...</div>}>
        <DynamicStock id={params.id} />
      </Suspense>
    </div>
  );
}

但有个大前提

PPR目前还是实验性功能,不建议在生产环境用。可以在非关键页面试试水,但别全站上。

等它稳定了(可能Next.js 16?),绝对是个大杀器。

这些新特性怎么和SSR/SSG/ISR配合?

  • RSC + SSG:Server Component默认就是静态的,和SSG配合完美
  • RSC + ISR:Server Component + revalidate,既静态又能定期更新
  • RSC + SSR:动态路由或设置dynamic = 'force-dynamic',就变成SSR了
  • PPR:可以看作SSG和SSR的终极融合

我的理解是:RSC是Next.js的底层架构升级,而SSG/SSR/ISR是基于这个架构的渲染策略。它们不冲突,反而相辅相成。

结论

说了这么多,咱们回到最开始的问题:SSR、SSG、ISR到底该怎么选?

其实没有标准答案。每个项目的需求不一样,流量不一样,预算也不一样。但只要你搞清楚这三个核心问题,选择就不难了:

  1. 内容需要个性化吗? → 需要就用SSR
  2. 内容多久更新一次? → 实时用SSR,定期更新用ISR,很少变化用SSG
  3. 流量有多大? → 超高流量优先SSG或ISR

还记得文章开头老板问我”为什么这么慢”的场景吗?后来我们把那个首页从SSR改成了ISR(revalidate: 60),首屏加载从3秒降到0.8秒。老板满意了,用户体验也好了。

我的建议是

  • 如果你不确定,先用ISR试试。它是三者中最平衡的,既快又能保持内容新鲜
  • 项目上线后,用Chrome DevTools的Performance面板实际测试一下,看看TTFB、FCP这些指标
  • 不同页面可以用不同策略,不要教条

最后,渲染策略不是一成不变的。项目发展了,用户量上去了,需求变了,策略也可以调整。别怕改,Next.js在这方面的切换成本其实挺低的。

希望这篇文章能帮你少踩点坑。如果你有什么实战经验或踩坑故事,欢迎留言分享!

常见问题

SSR、SSG、ISR 的核心区别是什么?
SSG 在构建时生成所有页面 HTML,用户访问时直接返回静态文件,TTFB 通常在 50ms 以内,速度快但内容更新需要重新构建。SSR 每次请求时实时生成 HTML,TTFB 通常在 200-500ms,内容最新但首屏加载慢。ISR 结合两者优势:构建时生成静态 HTML,根据 revalidate 时间后台自动更新,既有 SSG 的速度又有 SSR 的新鲜度。
什么时候用 SSG,什么时候用 SSR,什么时候用 ISR?
SSG:静态、公共、不常更新的页面(企业官网、产品介绍页、博客文章详情页)。SSR:动态、个性化、实时的页面(用户仪表盘、购物车、实时数据面板)。ISR:定期更新、可接受延迟、高流量的页面(博客首页、新闻网站、电商产品详情页)。决策口诀:静态用 SSG,实时用 SSR,定期更新用 ISR。不确定时先用 ISR。
ISR 的 revalidate 配置了为什么不生效?
常见原因有三个:1) 在开发环境(next dev)测试,ISR 只在生产环境(next build + next start)才工作,必须构建后再测试。2) 部署平台不支持,Vercel 原生支持,其他平台(如 Netlify)需要安装插件。3) CDN 缓存覆盖了 ISR,需要配置 CDN 尊重 Cache-Control 头。建议在生产环境测试,用 console.log(new Date()) 打印页面生成时间验证。
SSR 首屏加载慢怎么办?
优化方法:1) 使用 Streaming SSR 和 Suspense,先返回页面框架,数据到了再流式传输。2) 并行请求数据,用 Promise.all 替代串行请求。3) 考虑改用 ISR,如果数据延迟 1 分钟更新可以接受,ISR 能大幅提升性能(某案例从 3 秒降到 0.7 秒)。4) 部署到 Edge,使用 Edge Runtime 降低延迟。关键是分析瓶颈:API 调用慢、数据库查询慢、串行请求、服务器性能差。
SSG 构建时间太长怎么办?
解决方案:1) 使用 fallback 策略,只生成热门页面,其他页面按需生成(generateStaticParams 只返回热门内容,设置 dynamicParams = true)。2) 结合 ISR,构建时只生成首页和热门页面,其他页面用 ISR 按需生成。3) 使用增量构建(Vercel 支持,其他平台需自己实现)。实际案例:2000 篇文章从纯 SSG(15 分钟)改为 fallback + ISR(2 分钟),用户访问速度不变。
可以混合使用不同的渲染策略吗?
可以,而且这是最佳实践。不同页面可以用不同策略:首页和产品列表用 ISR(流量大,定期更新),产品详情用 SSG(内容稳定)或 ISR(价格库存会变),用户仪表盘用 SSR(个性化),关于我们页面用 SSG(完全静态)。实际项目案例:电商网站首页 ISR(10 分钟更新)、商品列表 ISR(5 分钟更新)、商品详情 ISR(3 分钟更新)、购物车 SSR(必须实时)、用户中心 SSR(个性化)、关于我们 SSG(几乎不变)。
React Server Components 和 SSR/SSG/ISR 是什么关系?
RSC 是 Next.js 的底层架构升级,SSG/SSR/ISR 是基于这个架构的渲染策略,它们相辅相成。RSC 默认在服务器端渲染,客户端 JavaScript 体积能减少 30-50%。配合方式:RSC + SSG(Server Component 默认静态,配合完美)、RSC + ISR(Server Component + revalidate,既静态又能定期更新)、RSC + SSR(动态路由或设置 dynamic = 'force-dynamic')。实战建议:默认用 Server Component,只在需要交互的地方用 Client Component(加 'use client')。

16 分钟阅读 · 发布于: 2025年12月19日 · 修改于: 2026年1月22日

评论

使用 GitHub 账号登录后即可评论

相关文章