← 返回题目列表

SSR 项目中的运行时配置和环境变量如何设计?

中等 第 18 / 25 题 更新于 2026/07/29
SSR环境变量运行时配置部署

简化版

SSR 项目要区分构建时配置和运行时配置。构建时配置会被打进产物,适合公开的静态值;运行时配置在服务启动或请求处理时读取,适合不同环境、不同租户、后端地址、灰度开关等。最重要的原则是:服务端密钥只能留在服务端,不能通过 HTML 注水或客户端 bundle 暴露给浏览器。

详细版

CSR 项目很多配置在 build 阶段就确定了,但 SSR 项目还有一个长期运行的服务进程,它可以在请求时读取环境变量、配置中心或请求上下文。

如果把所有配置都打包进前端代码,会导致环境切换困难、镜像复用能力差,也可能泄露密钥。更好的做法是把配置分层:公开配置给客户端,私密配置只在服务端使用,动态配置通过服务端接口或配置中心控制。

面试中要主动提“配置边界”:哪些能给客户端,哪些只能在 SSR server 内部使用。

完整版教学

一、先区分两类配置

构建时配置在打包时确定。

运行时配置在服务启动或请求过程中确定。

SSR 同时拥有浏览器 bundle 和服务端 bundle,所以配置泄露风险更高。

同一个变量名如果被错误注入客户端,可能直接出现在 JS 文件里。

二、配置分类

类型示例是否可暴露给客户端
公开配置CDN 地址、站点名称、公开 API base path可以
服务端配置内网 API 地址、数据库代理地址不应直接暴露
密钥配置OAuth secret、签名密钥、服务 token严禁暴露
动态开关灰度策略、实验配置看内容敏感度

三、为什么 SSR 更容易踩坑

SSR 代码可能同时被服务端和客户端引用。

如果把读取密钥的模块 import 到客户端组件,打包器可能把不该出现的内容带进产物。

有些框架用变量前缀区分公开变量和私密变量,例如 PUBLIC_ 之类。

命名规范和代码边界必须一起控制。

运行时配置的核心不是“能不能读环境变量”,而是“读到之后会不会被送到浏览器”。

四、代码示例

const serverConfig = {
  internalApi: process.env.INTERNAL_API_URL,
  oauthSecret: process.env.OAUTH_SECRET,
};

const publicConfig = {
  cdnBase: process.env.PUBLIC_CDN_BASE,
  appName: "Offer AIGC",
};

export function getPublicConfig() {
  return publicConfig;
}

服务端渲染时只把 publicConfig 注水给客户端。

不要为了方便把整个 process.env 序列化到页面里。

五、多环境部署策略

开发、测试、预发、生产应该有明确配置来源。

容器镜像最好可复用,环境差异通过运行时变量注入。

前端静态资源域名如果是构建时确定,就需要每个环境重新构建。

SSR 服务地址、接口网关、灰度开关更适合运行时读取。

六、和缓存的关系

运行时配置如果参与页面内容,就会影响缓存 key。

按地区、租户、语言输出不同 HTML 时,CDN 缓存必须区分这些维度。

如果灰度开关影响 HTML,也要避免不同用户拿到错误版本。

配置不是孤立问题,它会传导到缓存和回滚策略。

七、误区和追问

  • 误区:环境变量一定安全。 变量安全与否取决于它是否被打进客户端产物或注水到 HTML。
  • 误区:SSR 里所有配置都能运行时改。 构建进 bundle 的值通常需要重新构建或重启才生效。
  • 误区:公开变量前缀只是命名习惯。 在很多框架里,前缀会影响变量是否暴露到客户端。
  • 追问:如何检查密钥有没有泄露? 可以扫描构建产物、HTML 注水内容和 sourcemap,同时做 secret scanning。
  • 追问:配置变更需要重启吗? 环境变量通常需要重启,配置中心可做到动态刷新,但要处理一致性。
  • 追问:多租户 SSR 配置怎么做? 根据 host、路径或请求头选择租户配置,并把租户维度纳入缓存设计。

八、面试回答重点

把答案落到“构建时与运行时、服务端与客户端、公开与私密、配置与缓存”四组边界。

只要边界讲清楚,说明你理解 SSR 项目不只是前端打包。