CSR、SSR、SSG 与 Hydration:页面在哪里生成
打开知识库,先看到一块空壳,过一会儿正文才出现;另一个网站几乎马上就有文字,但按钮晚一点才可点。它们可能选择了不同的渲染方式。先区分“看见内容”和“可以交互”,再讨论哪种适合。
三种生成 HTML 的时机
| 方式 | 主要生成时机 | 适合讨论的场景 | 需要承担的成本 |
|---|---|---|---|
| CSR | 浏览器加载脚本之后 | 强交互后台、客户端工具 | 首屏脚本与请求等待 |
| SSR | 服务端收到请求时 | 动态公开内容、按请求生成页面 | 服务端计算、缓存与请求隔离 |
| SSG | 构建阶段 | 更新较少的文档、营销页面 | 内容更新后的重新生成 |
这些方案可以混用。公开文章采用预渲染或 SSR,编辑器采用客户端交互,并不矛盾。SSR 也可能附带很多 JavaScript,不能仅凭三个字母判断性能;SSG 也可以在客户端继续获取动态数据。
Hydration 是把交互接到已有 HTML 上
服务端先输出 HTML,客户端再用相匹配的数据和组件结构接管。若服务端输出时间 A、客户端第一次渲染用时间 B,或者服务器无登录信息而客户端直接展示用户菜单,就可能出现 hydration mismatch。
随机数、时区格式、无效 HTML 嵌套、浏览器扩展都可能造成首屏不一致。不要只压制警告,应定位两端初次输出为何不同。仅客户端需要的能力放到合适生命周期,且设计服务端占位输出。
服务器环境不是浏览器
SSR 中没有可直接使用的 window、document、localStorage。模块顶层访问这些对象可能在构建或请求时就崩溃。共享模块中的可变用户状态还可能串请求,应创建请求范围内的状态。
服务端生成页面也不等于可以随意缓存。用户私有文章若被公共 CDN 缓存,可能泄露给其他访客。缓存键、认证上下文和响应头必须配合,公开页面与个人工作区应分别设计策略。
怎么选
先列内容是否公开、更新频率、交互强度和部署约束。知识库正文需要直接访问、分享和搜索可见性,通常值得考虑服务端或预生成 HTML;管理员编辑器更关注草稿和交互,客户端逻辑会更多。选型目标是匹配需求,不是争论 SSR 是否“更高级”。
练习与参考
在练习页面渲染当前时间,故意让两端时区不同,观察 hydration 警告。随后改为明确传递同一初始值,或先渲染稳定占位再客户端更新,解释各自的用户体验。
用查看源码和关闭脚本理解三种模式
打开页面后,浏览器开发者工具 Elements 面板展示的是当前 DOM,可能已经被 JavaScript 改过;“查看网页源代码”或检查首个 HTML 响应,才更接近服务端实际返回的文档。不要看到 Elements 里有正文,就认定服务器发送了正文。
在练习环境关闭 JavaScript 再刷新:纯 CSR 页面可能只剩入口壳;SSR 或 SSG 页面通常仍能显示预生成的文字,但依赖脚本的收藏和筛选不能照常运行。原生链接和表单能否工作,还取决于页面是否提供了相应 HTML 与服务器端点。
Hydration 要匹配服务器输出与客户端首次计算。服务端输出“未登录”,客户端首轮立刻从本地存储读到用户并输出“你好”,就可能不匹配。可以传递一致的初始会话信息,或先显示稳定占位再在客户端确认状态,但不能把私密信息塞进公开缓存解决问题。
SSG 的“构建时生成”是基础定义;某些框架还能按需重新生成或缓存请求结果,那是额外机制,需要明确失效与更新条件。SSR 也可以被缓存,因此不能简单说“每个访客必然重新查一次数据库”。讨论性能时必须描述具体配置。
个性化设置先保证首屏一致
以正文大小为例:服务器不知道浏览器里保存了 18px 还是 20px。可以先统一输出默认字号,挂载后再读取本地偏好;需要首屏就准确显示时,可设计服务端也能读取的偏好来源,同时考虑缓存如何区分。
练习中分别开启和禁用本地存储,确认两种情况下文章都可阅读。再比较首个 HTML 响应与客户端初次渲染,不要仅凭页面最终看起来正常,就忽略 hydration 警告。框架能够恢复部分不匹配,不代表所有属性都会自动修好。
本节的核验依据
2026-10-25 查阅。下面的链接支持本节的机制说明;练习场景和选型建议是本教程的教学设计。