如何在React应用中访问Google Cloud Run环境变量
问题原因
React 应用中通过 process.env.REACT_APP_xxx 读取环境变量的逻辑是构建阶段硬编码的:执行 npm run build 打包时,构建工具(CRA/Vite等)会扫描代码里的 process.env.xxx 引用,直接替换成构建当时Node进程里对应的环境变量值,最终生成的是纯静态JS文件,运行在浏览器里时根本不存在process对象,自然读不到Cloud Run容器运行时才注入的环境变量。
你在Cloud Run控制台配置的环境变量仅在容器启动后的服务端运行环境生效,如果你是提前构建好React静态包再打包进容器镜像,构建阶段完全接触不到这些运行时配置,读取结果必然是undefined。
可行方案(无需本地提交.env文件)
核心思路是把环境变量的注入时机从「前端构建阶段」挪到「Cloud Run容器响应请求的运行时」,最稳定通用的实现是动态入口HTML注入全局配置,步骤如下:
- 改造前端配置读取逻辑
不再直接读取process.env,改为读取挂载在window上的运行时全局配置:// src/config.js export const BASE_FRONTEND_URL = window.__RUNTIME_CONFIG__.REACT_APP_BASE_FRONTEND_URL export const BASE_BACKEND_URL = window.__RUNTIME_CONFIG__.REACT_APP_BASE_BACKEND_URL - 新增轻量服务端逻辑托管静态资源
不用复杂的后端服务,只需要加一个几十行代码的静态文件服务,在返回入口index.html时,动态把容器里的环境变量注入到HTML中,挂到window对象上。以最常用的Express为例,新建server.js文件:const express = require('express'); const path = require('path'); const fs = require('fs'); const app = express(); // 托管React打包后的build目录下的静态资源 app.use(express.static(path.join(__dirname, 'build'))); // 所有前端路由返回处理后的index.html app.get('*', (req, res) => { // 仅筛选需要暴露给客户端的非敏感配置,严禁传入密钥、密码等敏感信息 const runtimeConfig = { REACT_APP_BASE_FRONTEND_URL: process.env.REACT_APP_BASE_FRONTEND_URL, REACT_APP_BASE_BACKEND_URL: process.env.REACT_APP_BASE_BACKEND_URL }; const indexPath = path.join(__dirname, 'build', 'index.html'); let htmlContent = fs.readFileSync(indexPath, 'utf-8'); // 在HTML头部插入全局配置脚本,确保前端代码加载时就能读取到配置 htmlContent = htmlContent.replace( '<head>', `<head><script>window.__RUNTIME_CONFIG__ = ${JSON.stringify(runtimeConfig)}</script>` ); res.send(htmlContent); }); // Cloud Run默认会注入PORT环境变量,直接监听即可 const PORT = process.env.PORT || 8080; app.listen(PORT, () => console.log(`Service running on port ${PORT}`)); - 调整部署配置
- 项目依赖里添加
express:执行npm i express - 修改启动命令:镜像启动时不再直接托管静态文件,改为执行
node server.js - 正常执行
npm run build打包React代码即可,构建阶段不需要传入任何环境变量 - 正常在Cloud Run控制台配置对应环境变量即可,不需要在项目中提交任何.env文件
- 项目依赖里添加
注意事项
- 所有注入到
window.__RUNTIME_CONFIG__的配置都是公开的,所有访问站点的用户都能在浏览器控制台看到,绝对不要把数据库密码、API密钥、服务账号凭证这类敏感信息通过这个方式暴露 - 后续修改Cloud Run控制台的环境变量后,Cloud Run会自动滚动更新实例,不需要重新构建前端代码,重启后新配置即可生效
- 如果不想引入Express,也可以通过Nginx的sub_filter模块实现同样的HTML注入逻辑,或者在容器启动时用脚本替换静态文件中的占位符,但前者配置更简单、缓存兼容性更好,优先推荐使用。
内容的提问来源于stack exchange,提问作者london_utku
相关产品推荐
相关产品推荐

