← 返回题目列表

SSR 中数据获取应该如何设计?

高频 中等 第 9 / 25 题 更新于 2026/07/28
SSR数据获取同构缓存

简化版

SSR 数据获取要在服务端渲染前拿到首屏所需数据,并把初始数据注入 HTML,客户端水合时复用这份数据,避免重复请求和水合不一致。还要处理缓存、错误、超时、鉴权和请求隔离。

详细版

SSR 数据获取关注:

  • 服务端根据 URL、Cookie、Header 获取数据。
  • 首屏必须数据在渲染前准备好。
  • 数据序列化注入页面。
  • 客户端初始化时复用注入数据。
  • 避免客户端再次请求导致闪烁。
  • 错误和超时要有兜底。
  • 用户相关数据不能被跨请求共享。

缓存策略要区分公共数据和用户私有数据。公共页面可缓存,个性化页面要谨慎。

完整版教学

一、SSR 为什么要提前取数据

SSR 的目标是返回带内容的 HTML。如果服务端不提前取数据,只返回空壳,优势就很小。

因此服务端渲染前需要知道当前路由需要哪些数据,并等待关键数据完成。

二、初始数据注入

服务端拿到数据后,不仅用于生成 HTML,还要把数据安全地注入页面,让客户端水合时复用。

如果客户端水合时重新请求,并且数据不同,就可能出现水合不一致或页面闪烁。

注入数据时要注意序列化安全,避免把用户内容直接变成可执行脚本。

三、请求隔离

SSR 是多用户请求共享同一个服务进程。不能把用户状态放到模块级全局变量里,否则可能出现 A 用户数据串到 B 用户页面的严重问题。

每个请求都应该创建独立上下文,包含 Cookie、Header、用户信息和请求级缓存。

四、面试追问与工程落地

面试官可能问:“SSR 接口慢会怎么样?”

接口慢会拖高 TTFB,用户更晚收到 HTML。解决方式包括缓存、超时降级、并行请求、流式渲染、只阻塞关键数据,非关键数据交给客户端加载。

工程中 SSR 数据层要统一处理超时和错误,否则一个接口慢可能拖垮整个页面。

五、避免瀑布并划分阻塞边界

服务端组件逐层发现请求会形成瀑布:用户接口 200ms 完成后才发商品接口 300ms,总等待约 500ms;若二者互不依赖并行启动,关键数据等待接近 max(200, 300)=300ms,理论上省约 200ms。

async function loadPageData(requestContext, productId) {
  const [user, product] = await Promise.all([
    getUser(requestContext),
    getProduct(productId),
  ])
  return { user, product }
}
数据类型是否阻塞首屏推荐策略
标题/正文服务端并行获取,失败有状态页
推荐列表流式 fallback 或客户端加载
用户权限通常是请求级上下文,禁止公共缓存
统计埋点不进入 SSR 关键路径

SSR 数据层的目标不是“服务端拿完所有数据”,而是用最少阻塞数据生成正确首屏,其余内容渐进补齐。

六、序列化、缓存和安全边界

把数据直接拼进 <script> 即使经过 JSON.stringify,仍要处理能提前结束 script 的字符序列和框架序列化协议。应使用框架提供的安全注入能力,只暴露客户端真正需要的字段,不能把数据库记录、内部 token 或服务端密钥整个塞进 HTML。

请求上下文
├─ Cookie/Header/用户身份(仅本请求)
├─ 请求级 memo(同次渲染去重)
├─ 公共数据缓存(明确 key/TTL)
└─ 初始客户端数据(最小化、安全序列化)

一次渲染中 5 个组件都取同一商品,应通过请求级 memo 合并为 1 次;跨请求公共商品可再缓存 60 秒。用户订单绝不能因为 URL 相同进入公共缓存,缓存 key 和数据分类要在数据层强制执行。

超时必须有总 deadline。页面预算 800ms 时,不能让三个接口各自串行等 800ms;关键请求并行并共享剩余预算,非关键模块超时后输出占位,才能控制 TTFB 尾延迟。

七、常见误区与追问

  • 误区:SSR 应等待页面所有接口后再返回。 只阻塞首屏正确性依赖的数据,低价值模块可流式或客户端加载。
  • 误区:JSON.stringify 后直接拼 script 永远安全。 特殊字符可能打断脚本上下文,应使用框架安全序列化并最小化字段。
  • 误区:模块级 Map 可以缓存所有用户请求。 长进程共享模块状态,可能造成跨用户数据泄露。
  • 追问:怎样避免客户端重复请求? 把服务端初始数据按框架协议传给客户端查询缓存或状态层,并使用一致 cache key。
  • 追问:为什么并行请求不总是更好? 下游容量、依赖关系和连接限制也要考虑,应只并行独立且必要的数据。
  • 追问:SSR 接口慢最先影响哪个指标? 通常直接抬高 TTFB,并延后 HTML 解析和后续资源发现。
  • 追问:请求级缓存与全局缓存有何区别? 前者只在一次渲染内去重,后者跨用户复用,安全和失效要求完全不同。

八、加强记忆

  1. 先分类:首屏关键、可流式、可客户端加载三类数据分开。
  2. 先启动:独立请求并行发出,避免组件树逐层瀑布。
  3. 请求隔离:身份、Cookie 和用户缓存只存在当前请求上下文。
  4. 安全传输:初始数据最小化并用框架安全序列化能力注入。
  5. 多层缓存:请求 memo 去重,公共缓存跨请求,私有数据禁止串用。
  6. 预算控制:统一 deadline、超时降级和可观测耗时保护 TTFB。