在 服务端渲染(Server-Side Rendering, SSR) 与 静态站点生成(Static Site Generation, SSG) 之间做出选择,会对 Web 性能和 SEO 产生重大影响。本指南对比了这两种方案,并为每种方案提供了优化策略。
渲染谱系
现代 Web 框架提供了多种渲染策略:
- 静态站点生成(SSG):在构建时预先生成
- 增量静态再生(Incremental Static Regeneration, ISR):静态生成并定期更新
- 服务端渲染(SSR):在每次请求时生成
- 客户端渲染(Client-Side Rendering, CSR):在浏览器中渲染
- 按需重新验证(On-Demand Revalidation):混合方案
SSG:性能与 SEO 的最佳选择
优势
- 最快的 TTFB(由 CDN 提供服务)
- 最佳的 Core Web Vitals 得分
- 对搜索引擎而言可完美抓取
- 降低服务器成本
- 可在边缘节点缓存
理想适用场景
- 博客文章与资讯文章
- 变更不频繁的产品页面
- 文档站点
- 落地页
- 营销类网站
SSG 实现(Next.js)
export async function getStaticProps() {
const posts = await fetchPosts();
return {
props: { posts },
revalidate: 3600, // ISR: regenerate every hour
};
}
SSR:当动态内容必不可少时
优势
- 内容始终保持最新
- 可提供个性化响应
- 适合频繁更新的数据
- 更适合面向特定用户的页面
SEO 方面的挑战
- 更高的 TTFB
- 服务器容量会影响抓取预算(crawl budget)
- 更难在边缘节点缓存
- 服务器较慢时存在爬虫超时风险
SSR 优化
// Cache SSR responses at edge
export async function getServerSideProps({ res }) {
const data = await fetchData();
res.setHeader('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300');
return { props: { data } };
}
混合渲染策略
最佳方案是将多种渲染方法组合使用:
| 页面类型 | 渲染方式 | 缓存 |
|---|---|---|
| 首页 | ISR | 5 分钟 |
| 博客文章 | SSG | 1 小时重新验证 |
| 产品页面 | ISR | 15 分钟重新验证 |
| 用户仪表盘 | SSR | 不缓存 |
| 搜索结果 | SSR | 1 分钟缓存 |
| API 路由 | SSR | 动态 |
各策略的性能优化
SSG 优化
- 在 HTML 中预加载关键资源
- 实现 service worker 以支持离线访问
- 使用具备地理分布的 CDN
- 优化构建产物的体积
SSR 优化
- 实现边缘缓存
- 使用流式 SSR 实现渐进式渲染
- 缓存数据库查询
- 使用连接池
- 实现服务端压缩
流式 SSR
// React 18 streaming SSR
import { renderToPipeableStream } from 'react-dom/server';
app.get('/', (req, res) => {
const stream = renderToPipeableStream(
<App />,
{
bootstrapScripts: ['/client.js'],
onShellReady() {
res.setHeader('content-type', 'text/html');
stream.pipe(res);
}
}
);
});
对 Core Web Vitals 的影响
| 指标 | SSG | SSR | CSR |
|---|---|---|---|
| LCP | 最佳 | 良好 | 较差 |
| FCP | 最佳 | 良好 | 较差 |
| INP | 相同 | 相同 | 较差 |
| CLS | 良好 | 良好 | 不稳定 |
| TTFB | 最佳 | 不稳定 | 不适用 |
抓取预算的考量
SSR 站点会消耗更多抓取预算:
- 服务器必须在抓取时渲染每个页面
- 响应缓慢会降低抓取频率
- 必要时在 robots.txt 中使用
Crawl-Delay - 实现 XML 站点地图以实现高效的页面发现
SSG 站点对爬虫更友好:
- 即时提供静态 HTML
- 爬虫可以快速请求页面
- 抓取不会给服务器带来负载
- 抓取效率更高