SSR/SSG 的定义 之前在博客上有提过。对比 CSR、SSR、SSG、ISR,它们的优缺点和适用场景分别是什么?

一、为什么要使用 SSR/SSG?(解决传统前端渲染的核心痛点)

传统 React/Vue 项目是「客户端渲染(CSR)」:浏览器先加载空 HTML → 下载 JS → 执行 JS 渲染页面,存在两大致命问题,而 SSR/SSG 能完美解决:

痛点(CSR 客户端渲染) SSR/SSG 的解决方案
白屏时间长,用户体验差 - SSR:服务器返回完整 HTML,浏览器直接渲染,首屏无白屏;- SSG:预生成静态 HTML,加载速度比 SSR 更快(静态文件可放 CDN)。
SEO 不友好,爬虫抓不到内容 爬虫直接抓取服务器返回的完整 HTML(含页面内容),而非空壳 HTML,百度 / 谷歌能正常索引页面。
首屏性能指标差(LCP/FCP 高) 首屏渲染时间(LCP)大幅降低,符合核心 Web 指标要求,提升页面排名。
弱网 / 低配置设备体验差 低配置手机 / 弱网环境下,无需等待 JS 下载执行,先看到内容,体验更优。

二、SSR vs SSG 适用场景(选对才有用)

特性 SSR(服务端渲染) SSG(静态生成)
渲染时机 每次用户请求时(运行时) 项目构建时(预渲染)
性能 较快(动态渲染有开销) 极快(静态文件,CDN 分发)
动态内容支持 完美支持(如用户中心、实时数据、个性化内容) 仅支持静态内容(如官网、博客、文档、商品列表(非实时))
部署复杂度 较高(需服务器运行 Node.js 等环境) 极低(静态文件可部署到任何静态托管平台:GitHub Pages/Vercel/Netlify)
维护成本 较高(需维护服务端环境) 极低(静态文件无运行时依赖)

典型适用场景:

  • 用 SSG:企业官网、博客、文档站、产品介绍页、帮助中心(内容固定 / 更新频率低);
  • 用 SSR:电商商品详情页(部分动态)、用户中心、后台管理系统(需登录)、实时数据看板;
  • 用 ISR:电商商品页(构建时预生成,数据更新时增量刷新)、新闻资讯页(定时更新)。

三、什么时候不用 SSR/SSG?

  • 纯后台管理系统(无需 SEO,仅内部使用);
  • 内容高度动态且更新极频繁(如实时聊天、股票行情)→ 用 CSR + 首屏骨架屏更合适;
  • 小项目 / 原型(SSR/SSG 增加开发 / 部署成本,性价比低)。

四、核心总结

  • SSG:为「静态内容」而生,极致性能 + 极简部署,优先选;
  • SSR:为「动态内容」而生,解决白屏 + SEO,部署稍复杂;

两者核心价值:提升首屏体验 + 优化 SEO,是生产环境 React/Vue 项目的标配方案(尤其 ToC 业务)。

五、基于Next.js实现SSR/SSG

步骤 1:初始化 Next.js 项目

1
2
3
4
5
6
# 创建 Next.js 项目(默认支持 React 18)
npx create-next-app@latest my-ssr-app
# 进入项目
cd my-ssr-app
# 启动开发服务
npm run dev

步骤 2:实现 SSG(静态生成)

SSGNext.js 默认的渲染方式,通过 getStaticProps(页面级数据预取) + 构建时预渲染实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// pages/index.js(Next.js 12/13 兼容,App Router 见下文)
export default function Home({ posts }) {
return (
<div>
<h1>静态生成的博客列表</h1>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

// 核心:构建时执行,预取静态数据(SSG 关键)
export async function getStaticProps() {
// 模拟从接口/数据库获取数据(构建时执行)
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

// 返回数据给组件,构建时预渲染为 HTML
return {
props: { posts },
// ISR 配置(可选):60秒内重复请求复用静态页面,超时后重新生成
revalidate: 60
};
}

构建 & 验证 SSG:

1
2
3
4
# 构建静态页面(生成 .next/static 目录)
npm run build
# 启动生产服务
npm run start

构建后,pages 下的所有页面会被预渲染为静态 HTML,访问时无白屏,SEO 友好。

步骤 3:实现 SSR(服务端渲染)

通过 getServerSideProps 替代 getStaticProps,每次请求时服务端动态渲染:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// pages/user.js(用户中心,动态内容)
export default function User({ userInfo }) {
return (
<div>
<h1>用户中心(SSR 渲染)</h1>
<p>用户名:{userInfo.name}</p>
</div>
);
}

// 核心:每次请求时执行,动态获取数据(SSR 关键)
export async function getServerSideProps(context) {
// context 包含请求信息(如 cookie、query、headers)
const { req, res, query } = context;
// 模拟从接口获取用户数据(基于请求的 cookie/token)
const res = await fetch('https://api.example.com/user', {
headers: { cookie: req.headers.cookie }
});
const userInfo = await res.json();

// 返回数据,服务端实时渲染为 HTML
return { props: { userInfo } };
}

验证 SSR:启动服务后访问 http://localhost:3000/user,查看页面源码(能看到完整的用户信息 HTML),且每次刷新都会触发 getServerSideProps 重新获取数据。

Next.js 13+ App Router 适配(最新推荐)

Next.js 13 推出了 App Router,用「React Server Components(RSC)」简化 SSR/SSG,核心逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// app/page.js(默认 SSG,App Router 入口)
// 直接写异步组件,构建时预取数据(替代 getStaticProps)
async function getPosts() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
cache: 'force-cache' // 默认为 SSG(缓存数据)
// cache: 'no-store' // 改为 SSR(每次请求重新获取)
// next: { revalidate: 60 } // ISR(60秒缓存)
});
return res.json();
}

export default async function Home() {
const posts = await getPosts(); // 构建时执行(SSG)
return (
<div>
<h1>App Router 静态生成</h1>
{posts.map(post => <div key={post.id}>{post.title}</div>)}
</div>
);
}

关键配置(App Router):

  • cache: 'force-cache':默认 SSG,构建时缓存数据;
  • cache: 'no-store':SSR,每次请求重新获取数据;
  • next: { revalidate: 60 }:ISR,60 秒后重新生成页面。