← 返回题目列表

流式 SSR 是什么?它解决了什么问题?

高频 困难 第 12 / 25 题 更新于 2026/08/03
SSR流式渲染性能优化

简化版

流式 SSR 是服务器不等整页 HTML 全部生成完再返回,而是边渲染边把 HTML 分块发送给浏览器。它能更早输出页面骨架和已完成内容,降低用户等待感,适合数据依赖复杂或页面较大的场景。

详细版

传统 SSR 可能要等所有数据和组件渲染完成,才返回完整 HTML。如果某个非关键接口慢,会拖住整页。

流式 SSR 的思路:

  • 先发送页面外壳和关键内容。
  • 慢数据区域显示 fallback。
  • 数据准备好后继续流式输出。
  • 浏览器逐步接收和渲染。

优点:

  • 更早开始传输 HTML。
  • 降低 TTFB 或改善内容可见时间。
  • 慢组件不一定阻塞整页。

代价是错误处理、缓存、SEO、监控和框架支持更复杂。

完整版教学

一、传统 SSR 的阻塞问题

如果整页有多个数据源,传统 SSR 常需要等所有数据完成后才能生成 HTML。

一个低优先级模块接口慢,可能让整个页面都迟迟不返回。这会让用户长时间空白等待。

二、流式 SSR 的核心

流式 SSR 把 HTML 当作流发送。服务器先输出已经准备好的部分,浏览器边接收边解析。

框架可以配合 Suspense 或类似机制,让慢组件先输出占位内容,数据回来后再补齐。

这让页面从“等整桌菜上齐再开饭”,变成“先上主菜,配菜慢慢补”。

三、复杂度

流式渲染对工程要求更高。中途出错时页面可能已经发出一部分,不能像普通 SSR 那样简单改状态码或返回错误页。

缓存也更复杂,因为页面不是一次性完整生成。监控也要区分首字节、首块内容、完整内容。

四、面试追问与工程落地

面试官可能问:“所有页面都适合流式 SSR 吗?”

不适合。简单页面、静态页面、数据很快的页面没必要引入复杂度。流式 SSR 更适合内容多、数据源多、部分模块慢但首屏关键内容可以先展示的页面。

工程中要先解决基础 SSR 稳定性,再考虑流式能力。

五、分块时间线与背压机制

假设页面外壳 50ms 可生成,主体 API 200ms,推荐 API 1500ms。传统等待全部约 1500ms 才开始返回;流式方案可在 50ms 发 shell、200ms 发主体、1500ms 再替换推荐 fallback。

50ms  [HTML shell + fallback] ───────────────→
200ms [主体内容 chunk] ─────────────────────→
1500ms[推荐模块 chunk + 完成标记] ──────────→
指标含义流式优化目标
TTFB首字节到达尽早发 shell
首个有意义块关键内容出现关键边界优先
all content全部流结束慢模块不阻首屏
hydration ready交互可用控制脚本与调度

服务器写入速度超过客户端读取速度时必须尊重 stream 背压,否则慢客户端会让缓冲区和内存持续增长。流式不是不断 write 而不看返回状态。

流式 SSR 的价值是重排等待:让关键内容先穿过管道;它不会自动缩短慢接口本身的 1500ms。

六、状态码、缓存、代理与 SEO 边界

首块发送后响应头和状态码通常已经锁定,因此 404、重定向、关键权限应尽量在 shell 前判断。后续边界失败只能发送局部错误标记、保持 fallback 或让客户端恢复,并记录服务器错误。

代理/CDN 可能缓冲小 chunk,导致服务器在 50ms 写出而浏览器 1500ms 才一次收到。验收要在真实网关后观察网络分块、压缩和 flush 行为,不能只在本地 Node 直连测试。

完整 HTML 缓存可以在首次流式生成后存储,后续直接命中;边生成边 CDN 缓存则依平台能力。缓存 key、失败的半截响应、断开清理和爬虫是否等待完整流都要验证。

数据边界设计:
关键身份/标题 ── shell 前完成
主体内容 ────── 首个 Suspense 边界
推荐/评论 ───── 后续边界或客户端加载

七、常见误区与追问

  • 误区:流式 SSR 会让所有接口本身执行更快。 它让已完成内容提前发送,慢接口耗时并未消失。
  • 误区:服务端每次 write 都会立刻到浏览器。 压缩器、代理、CDN 和 TCP 缓冲都可能合并 chunk。
  • 误区:开始流式后还能随意改成 404/500。 头已提交时状态码无法正常改写,关键判断要前置。
  • 追问:什么页面适合流式? 数据边界可拆、关键内容能先完成、非关键模块明显较慢的页面。
  • 追问:如何处理客户端断开? 传播 abort,取消下游请求和渲染,释放流与请求级资源。
  • 追问:背压为什么重要? 慢客户端消费不及写入时,无界缓冲会放大服务器内存。
  • 追问:如何证明代理没有吞掉流式收益? 在生产链路抓取 chunk 到达时间,并对比直连与 CDN 后指标。

八、加强记忆

  1. 核心思想:HTML 分块输出,shell 和关键内容先到,慢模块后补。
  2. 边界划分:首屏关键数据、可延迟模块和客户端模块分层。
  3. 指标拆分:TTFB、首个有意义块、关键内容、全量完成、水合分别测。
  4. 协议约束:首块后状态码锁定,中途错误只能局部恢复。
  5. 流量控制:尊重背压,客户端断开要取消渲染和下游请求。
  6. 全链路验收:框架、压缩、代理、CDN、缓存和爬虫一起验证。