非create-react-app项目客户端如何访问Node.js服务端环境变量
问题根源
dotenv是Node.js服务端专属的运行时工具,仅会将.env文件内的变量注入到服务端进程的process.env对象中,浏览器环境运行的客户端代码原生不存在该对象,无法直接读取服务端进程内的变量。- 你能正常访问
process.env.NODE_ENV,是因为各类前端构建工具默认会对该字符串做静态硬编码替换,并非客户端具备读取服务端全量环境变量的能力,其余自定义变量不会被自动替换。 - 所有透传给客户端的环境变量必须做白名单过滤,严禁直接暴露全量
process.env,避免数据库密码、接口密钥等敏感信息泄露。
可行方案
以下两个方案均不需要依赖create-react-app,也不会出现webpack安装后的大量依赖报错问题,按需选择即可。
方案1:构建时静态注入(适配原有客户端代码写法,零业务代码改动)
该方案通过轻量构建工具在打包客户端代码时,直接将指定环境变量替换为静态值,客户端代码可以继续沿用process.env.xxx的写法,不需要调整业务逻辑。
- 在原有服务端
config.js中单独拆分客户端可访问的公开变量白名单,仅放入非敏感的客户端所需变量:const dotenv = require('dotenv'); const path = require('path'); dotenv.config({ path: path.resolve(__dirname, `../environments/${process.env.NODE_ENV.trim()}.env`) }); // 服务端自用配置,不对外暴露 const serverConfig = { NODE_ENV: process.env.NODE_ENV || 'development', DEF_USER: process.env.DEF_USER || 'admin' }; // 仅客户端可访问的非敏感变量,做构建替换用 const clientDefine = { "process.env.NODE_ENV": JSON.stringify(serverConfig.NODE_ENV), "process.env.DEF_USER": JSON.stringify(serverConfig.DEF_USER) }; module.exports = { ...serverConfig, clientDefine }; - 替换易报错的webpack为零配置轻量构建工具esbuild,安装依赖:
npm install esbuild --save-dev - 编写极简客户端构建脚本,直接引入白名单变量做注入:
// scripts/build-client.js const esbuild = require('esbuild'); const { clientDefine } = require('../config'); esbuild.build({ entryPoints: ['../client/src/index.js'], // 替换为你的客户端入口文件实际路径 bundle: true, outfile: '../client/dist/bundle.js', // 替换为客户端构建产物输出路径 define: clientDefine, // 构建时自动替换代码中对应的process.env字段 minify: process.env.NODE_ENV === 'production' }).catch(() => process.exit(1)); - 后续构建客户端时直接执行
node scripts/build-client.js即可,客户端代码中可直接通过process.env.DEF_USER获取对应值。
方案2:运行时接口下发(零构建配置改动,灵活度最高)
如果不想调整任何前端构建逻辑,直接通过服务端接口下发公开环境变量即可,不需要安装额外构建工具。
- 在服务端新增公开路由,仅返回白名单内的非敏感变量(以Express框架为例,其他框架逻辑一致):
// 服务端路由配置 app.get('/api/public-env', (req, res) => { res.json({ DEF_USER: process.env.DEF_USER || 'admin', NODE_ENV: process.env.NODE_ENV || 'development' // 仅在此处添加客户端需要的非敏感变量,禁止传入密钥、数据库连接串等敏感配置 }) }) - 客户端初始化阶段先请求该接口,拿到变量后存入全局供业务代码调用:
// 客户端入口初始化逻辑 window.publicEnv = {}; async function bootstrap() { const resp = await fetch('/api/public-env'); window.publicEnv = await resp.json(); // 后续业务代码通过window.publicEnv.DEF_USER即可获取对应值 // 追加其余应用初始化逻辑 } bootstrap();
该方案无需重新构建客户端即可生效,调整环境变量后仅需重启服务端,适合迭代频繁的场景。
避坑提示
- 禁止在客户端代码中直接引入服务端的
config.js文件,否则构建时会将服务端配置、dotenv相关依赖全部打包进客户端产物,极易造成敏感信息泄露。 - 所有暴露给客户端的变量必须提前做白名单校验,严禁直接返回全量
process.env对象。
内容的提问来源于stack exchange,提问作者Daniel Corona
相关产品推荐
相关产品推荐

