CSR、SSR 与 SSG:从系统权衡出发选择前端渲染策略
面向高级前端工程师的渲染策略分析:从性能、SEO、缓存、成本与工程复杂度系统比较 CSR、SSR 和 SSG。
很多团队讨论渲染方案时,习惯把它当成“框架偏好”。这其实不准确。渲染本质上是内容交付策略:HTML 在哪里生成、数据在什么时候完成解析、缓存放在哪一层、延迟成本由谁承担。
当你不再把 CSR、SSR、SSG 视为页面模板选项,而是把它们当成系统级架构决策时,很多争论会自然消失。
先用一句足够准确的话定义三者
- CSR:浏览器下载 JavaScript,拉取数据,并在客户端完成渲染。
- SSR:服务端按请求生成 HTML,浏览器接收后再完成 hydration。
- SSG:在构建期或再生成阶段提前产出 HTML,并以静态资源方式分发。
如果只停留在这三句话,仍然不够。真正影响用户体验的是完整链路:
CSR
浏览器 -> HTML 壳 -> JS Bundle -> API 请求 -> 渲染 -> 可交互
SSR
浏览器 -> 服务端带数据渲染 -> HTML -> Hydration -> 可交互
SSG
浏览器 -> CDN/静态 HTML -> 如有需要再 Hydration -> 可交互同一个站点甚至同一个页面,也完全可以混合使用多种策略。比如静态外壳加局部客户端交互,或服务端首屏加延迟加载模块,往往比“全站只选一种”更专业。
CSR:当浏览器才是真正运行时,它往往是最佳方案
如果页面高度个性化、SEO 不重要、交互状态复杂,且产品更像一个持续运行的客户端应用,而不是一篇文档,那么 CSR 通常是合理默认值。
典型场景包括:
- 登录后的后台系统
- 内部运营平台
- 协同编辑或高频状态更新工具
- 富交互图表、拖拽、编辑器、离线能力较强的产品
CSR 的优势
CSR 把首屏之后的大量工作交给浏览器。一旦应用启动完成,后续路由切换可以非常流畅,因为运行时、状态和缓存已经留在客户端。
同时,服务端可以专注于提供 API,而不是为每个请求承担完整的视图拼装。
CSR 的代价
CSR 的问题不在“能不能做”,而在“成本由谁承担”。浏览器要负责:
- 下载 JavaScript
- 解析与编译脚本
- 执行启动逻辑
- 请求数据并管理状态
这意味着在中低端移动设备上,CSR 的实际体验经常比本地开发时看到的差很多。即使 TTFB 不高,LCP 和可交互时间仍然可能被 JavaScript 执行成本拖慢。
CSR 最常见的失败模式
最典型的反模式,是页面先给出一个空壳和 loading,再层层串行请求数据:
HTML 壳
-> 应用 Bundle
-> 用户信息 API
-> 权限 API
-> 页面数据 API
-> 渲染这不是“前端架构现代化”,而是把延迟逐级放大。
SSR:当请求上下文会改变文档本身时,SSR 才真正有价值
SSR 适合这样的页面:如果没有请求时上下文,服务端就无法产出有意义的首屏 HTML。
常见例子:
- 首屏依赖登录态、地域、实验分流的页面
- 搜索结果页、筛选列表页
- 既要求 SEO,又要求首屏数据足够新鲜的内容页
- 价格、库存、促销变动频繁的电商页面
SSR 能解决什么问题
它能让用户更早拿到有语义的 HTML,同时让搜索引擎、社交抓取器、预览机器人在不执行客户端逻辑的情况下看到完整内容。
另外,鉴权、国际化、实验分流、服务端聚合数据等逻辑,都能在浏览器开始执行前完成。
SSR 的真正成本
SSR 的代价不是抽象的“服务端更辛苦一点”,而是把很多请求都变成了潜在计算:
- 服务端或边缘节点执行渲染
- 上游数据源延迟直接进入首屏链路
- 页面差异过大时缓存命中率下降
- 在高并发下更容易暴露系统瓶颈
一个页面单次服务端渲染耗时 300ms,看起来不算夸张;但当并发上来,这 300ms 会被真实放大成机器成本和尾延迟问题。
判断 SSR 是否成立,关键不在“能渲”,而在“能不能缓存”
高级团队不会只问“这个页面是否适合 SSR”,而是会继续追问:
- 生成后的 HTML 能否公共缓存?
- 请求差异由哪些维度决定?
- 数据缓存是否能与 HTML 缓存拆开?
- 是否能流式返回,或把次要模块延迟到后面?
如果这些问题全部回答不了,SSR 很容易退化成一种昂贵但并不优雅的页面交付方式。
SSG:对稳定型公共内容而言,通常是最强默认值
对于“更新频率远低于访问频率”的页面,SSG 往往是最佳解。
例如:
- 博客
- 文档
- 官网营销页
- 作品集
- 有明确发布节奏的产品介绍页
为什么 SSG 在很多真实系统里依然最优
因为它天然拥有最稳的性能轮廓:
- 静态 HTML 直接走 CDN
- 缓存策略简单清晰
- SEO 友好
- 服务端计算成本极低
- 流量上来时尾延迟更稳定
所以成熟团队通常会有“静态优先”的倾向。不是因为 SSG 时髦,而是因为很多页面根本不需要按请求重新计算,它们只需要合理的发布和再验证机制。
对 SSG 的常见误解
很多人把 SSG 理解成“只能发版时更新”。这已经过时了。现代站点完全可以:
- 定时再生成
- 内容变更后按需再生成
- 在 CMS webhook 触发后局部刷新
真正要判断的不是“能不能更新”,而是“业务对新鲜度的要求到底是秒级、分钟级还是小时级”。
先给结论,再谈细节
- 如果首屏 SEO 很重要,通常 SSR 和 SSG 比纯 CSR 更稳妥。
- 如果首屏必须反映用户私有数据或请求时上下文,通常 SSR 比 SSG 更合适。
- 如果最看重基础设施成本和缓存命中率,SSG 往往是最佳默认值。
- 如果页面在加载后本质上是一个重交互应用,CSR 依然非常有效。
- 对内容型公共站点,SSG 通常最合适。
- 对内部后台和登录后工具,CSR 往往是更自然的选择。
如果只想记一个顺序,可以记成一句话:公共内容优先静态化,首屏依赖请求上下文时再引入服务端渲染,浏览器本身就是主要运行时时再把重心交给 CSR。
评价渲染策略,必须用对指标
很多团队争论不休,本质上是拿错了指标。
对于公共内容页,应重点看:
- LCP
- INP
- CLS
- 抓取质量与元信息完整度
- CDN 命中率
对于业务系统页面,还要增加:
- 登录后的路由切换耗时
- API 往返次数
- 各路由 Bundle 体积
- 真实设备上的 Hydration 成本
如果你的比较标准只是“我在本机打开感觉挺快”,那通常会高估 CSR,低估高质量 HTML 首屏的价值。
混合渲染才是现代前端的常态
在成熟项目里,更常见的不是单选题,而是组合拳:
- 官网和营销页用 SSG
- 博客和文档用 SSG 加定时或按需再生成
- 搜索、列表、实时性较强页面用 SSR 或可缓存的服务端渲染
- 登录后控制台以 CSR 为主
- 公共布局尽量轻,避免整站 Hydration 负担失控
这种做法的本质,是让业务需求映射到渲染成本,而不是把一种技术姿势强行套到所有页面上。
选择时真正该问的问题
页面是否依赖请求时的私有数据或高频波动数据?
是 -> 优先考虑 SSR 或 CSR
否 -> 优先考虑 SSG
首屏 SEO 是否重要?
是 -> 优先 SSG 或 SSR
否 -> CSR 的适用面会更大
页面在首屏之后是否更像应用而不是文档?
是 -> 保持首屏轻量,把复杂交互留给客户端
否 -> 控制 JavaScript,优先交付预渲染 HTML资深团队也常犯的四个错误
1. 用 SSR 掩盖 API 设计问题
如果一个页面为了首屏渲染,要串行调用多个内部服务,那问题大概率是后端聚合层设计不合理,而不是“还需要更强的 SSR”。
2. 给文档型页面上重 CSR
如果博客、官网、介绍页只有极少量交互,却加载大量客户端运行时,那么用户承担的是 CPU 成本,而业务几乎没有收益。
3. 把 SSG 误判为“不够新鲜”
多数内容根本不需要按请求刷新。事件驱动再生成往往已经足够。
4. 忽略 Hydration 预算
页面可能很快返回 HTML,但仍然“看得见,点不动”。根因不是 SSR 或 SSG 失效,而是客户端 JavaScript 超预算了。
最后的判断标准
对大多数团队,一个稳健的顺序通常仍然是:
- 公共内容优先 SSG
- 只有当请求时上下文会改变文档本身时,再引入 SSR
- 当浏览器确实承担主要应用运行时职责时,使用 CSR
渲染策略从来不是信仰问题,而是延迟、缓存和复杂度在不同层之间的分配问题。真正成熟的做法,不是给整个站点贴一个统一标签,而是逐页决定哪一层负责计算,哪一层负责缓存,以及哪一层负责交互。
Nuxt vs Next:不要按功能清单比较,而要按框架运行模型比较
更新Vite vs Webpack:开发速度并不等于构建架构优劣