You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React应用index.html运行时注入服务URL的实现疑问

在Express中实现Create React App运行时环境变量注入

问题背景

我想按Create React App的要求,在运行时从服务器向页面注入数据,而非构建时硬编码环境变量。但如果用EJS的<%=SERVICE_A_URL%>这类模板语法,React构建过程会识别并报错,无法生成正常的index.html。需要用类似__SERVER_DATA__的自定义占位符,请问在Express里怎么实现运行时替换?

注:虽然通过API动态获取URL是更优方案,但当前应用需要大量重构,所以优先选择在index.html中替换占位符的方式。

我的现有Express代码如下:

import express, {Request, Response} from 'express';
import ejs from 'ejs';

const app = express();
app.engine('html', ejs.renderFile);

const renderIndexHtmlWithServiceUrls = (req: Request, res: Response) => {
    res.render('index.html', {
        SERVICE_A_URL: process.env.SERVICE_A_URL,
        SERVICE_B_URL: process.env.SERVICE_B_URL,
        cache: true
    })
}
app.get('/', renderIndexHtmlWithServiceUrls)
app.get('/index.html', renderIndexHtmlWithServiceUrls)

// Serve built react app
app.use(express.static("/build"));

...

解决方案

方法一:手动读取文件替换占位符(无额外依赖)

不需要引入新库,直接用Node.js的文件系统模块实现替换,适合占位符数量少的场景。

  1. 修改index.html的占位符
    把原来的EJS语法换成自定义的占位符,比如__SERVICE_A_URL__:
<script type="text/javascript">
  // Runs before react application.
  window.SERVICE_A_URL = "__SERVICE_A_URL__";
  window.SERVICE_B_URL = "__SERVICE_B_URL__";
  console.log(window.SERVICE_A_URL, window.SERVICE_B_URL);
</script>
  1. 修改Express代码
import express, { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';

const app = express();

// 读取build目录下的index.html并缓存(文件不常更新时用)
const indexHtmlPath = path.resolve(__dirname, '../build/index.html');
let indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf8');

const renderIndexHtmlWithServiceUrls = (req: Request, res: Response) => {
  // 替换占位符
  const modifiedHtml = indexHtmlContent
    .replace('__SERVICE_A_URL__', process.env.SERVICE_A_URL || '')
    .replace('__SERVICE_B_URL__', process.env.SERVICE_B_URL || '');
  
  res.send(modifiedHtml);
};

app.get('/', renderIndexHtmlWithServiceUrls);
app.get('/index.html', renderIndexHtmlWithServiceUrls);

// 静态资源服务
app.use(express.static(path.resolve(__dirname, '../build')));

// ... 其他服务器配置

如果index.html会频繁更新,可以把fs.readFileSync移到请求处理函数里,但会增加每次请求的IO开销,根据实际情况选择。

方法二:用replace-in-file批量替换占位符

如果需要替换大量占位符,手动写replace会很繁琐,可以用replace-in-file库批量处理。

  1. 安装依赖
npm install replace-in-file --save
  1. 修改Express代码
import express, { Request, Response } from 'express';
import replace from 'replace-in-file';
import path from 'path';

const app = express();

const indexHtmlPath = path.resolve(__dirname, '../build/index.html');

const renderIndexHtmlWithServiceUrls = async (req: Request, res: Response) => {
  try {
    const options = {
      files: indexHtmlPath,
      // 匹配占位符的正则(全局替换)
      from: [/__SERVICE_A_URL__/g, /__SERVICE_B_URL__/g],
      // 替换为对应的环境变量
      to: [process.env.SERVICE_A_URL || '', process.env.SERVICE_B_URL || ''],
      // 仅返回修改后的内容,不修改原文件
      dry: true
    };

    const results = await replace(options);
    res.send(results[0].contents);
  } catch (error) {
    console.error('占位符替换失败:', error);
    res.status(500).send('服务器错误');
  }
};

app.get('/', renderIndexHtmlWithServiceUrls);
app.get('/index.html', renderIndexHtmlWithServiceUrls);

app.use(express.static(path.resolve(__dirname, '../build')));

// ... 其他配置

方法三:调整EJS分隔符避免React冲突

如果还是想用EJS,可以修改EJS的默认分隔符,让React构建时忽略它。

  1. 修改Express的EJS配置
import express, { Request, Response } from 'express';
import ejs from 'ejs';
import path from 'path';

const app = express();

// 把EJS的分隔符改成[[和]],避免和React语法冲突
ejs.delimiter = '[';
ejs.openDelimiter = '[';
ejs.closeDelimiter = ']';

app.engine('html', ejs.renderFile);
app.set('view engine', 'html');
app.set('views', path.resolve(__dirname, '../build'));

const renderIndexHtmlWithServiceUrls = (req: Request, res: Response) => {
  res.render('index.html', {
    SERVICE_A_URL: process.env.SERVICE_A_URL || '',
    SERVICE_B_URL: process.env.SERVICE_B_URL || '',
    cache: true
  });
};

app.get('/', renderIndexHtmlWithServiceUrls);
app.get('/index.html', renderIndexHtmlWithServiceUrls);

app.use(express.static(path.resolve(__dirname, '../build')));

// ... 其他配置
  1. 修改index.html的占位符
<script type="text/javascript">
  window.SERVICE_A_URL = "[[= SERVICE_A_URL ]]";
  window.SERVICE_B_URL = "[[= SERVICE_B_URL ]]";
</script>

这样React构建时不会识别[[= ... ]]的语法,而Express的EJS可以正常替换这些占位符。


内容的提问来源于stack exchange,提问作者Ben Butterworth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:20:26