在 Express 中使用客户端路由为多个 React 应用程序提供服务

IT技术 node.js reactjs express
2021-04-09 17:34:04

我有针对一项服务的不同软件产品,需要将其部署到单个服务器。客户端使用 react 构建,通过 create-react-app 构建设置,而服务器运行 Node.js 和 Express。

当我从服务器提供单个应用程序时,它是通过以下方式完成的:

// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);

if(process.env.NODE_ENV !== 'development') {
  app.use(express.static(path.join(__dirname, 'build-client')));

  app.get('/*', function(req, res) {
    return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
  });
}

我希望能够从服务器提供多个应用程序。我该怎么做?

我尝试的是为资产连接不同的静态路径,并将具有不同名称的客户端分开,尽管它不起作用。像这样:

// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);

if(process.env.NODE_ENV !== 'development') {
  app.use(express.static(path.join(__dirname, 'build-client')));
  app.use(express.static(path.join(__dirname, 'build-admin')));

  app.get('/client/*', function(req, res) {
    return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
  });
  app.get('/admin/*', function(req, res) {
    return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
  });
}

我也尝试过这样做,但是 Express 抛出错误:未指定默认引擎且未提供扩展名:

if(process.env.NODE_ENV !== 'development') {
  // Admin paths
  app.use('/admin', express.static(path.join(__dirname, 'build-admin')));
  app.get('/admin/*', function(req, res) {
    return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
  });

  // Site paths
  app.use('/', express.static(path.join(__dirname, 'build-client')));
  app.get('/*', function(req, res) {
    return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
  });
}

我怎么能做到这一点或类似的东西?

2个回答

经过一些修补后,我能够在不使用虚拟主机的情况下实现这一目标。我使用了您在问题中给出的第一个想法,但我将主应用程序留在了根目录(即/)。

// when going to `/app2`, serve the files at app2/build/* as static files
app.use('/app2', express.static(path.join(__dirname, 'app2/build')))
// when going to `/`, serve the files at mainApp/build/* as static files
app.use(express.static(path.join(__dirname, 'mainApp/build')))


// These are necessary for routing within react
app.get('app2/*', (req, res) => {
  res.sendFile(path.join(__dirname + '/app2/build/index.html'))
})

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname + '/mainApp/build/index.html'));
});

在此之后,我进入mainApp/package.json并添加

"proxy": "http://localhost:4141"

:4141是快速服务器运行的端口。此行将调用fetch('/some/route')返回服务器而不是您的 React 应用程序本身。

最后,我们去app2/package.json添加

"proxy": "http://localhost:4141/app2",
"homepage": "/app2"

我相信这里的"homepage"关键关键。根据我的理解,当 React 启动时,它会在其主页上搜索一些静态文件,如果没有这个文件,"homepage"我只能得到一个空白屏幕或 mainApp。

我希望这可以帮助那里的人!


编辑

从那以后,我从通过我的 express 服务器为我的 create-react-apps 提供服务更改为通过netlify为它们提供服务现在我不需要担心这个快速设置,或者package.json. express 服务器是独立存在的,react 应用仍然可以使用相同的 api,并且部署更容易。使用 netlify 进行设置很简单。

在解决这个问题一段时间后,我找到了一个不影响原始设置的可能解决方案。

我们使用Express vhost 包来设置通过虚拟域处理请求。

当你创建你的应用程序实例时,你应该初始化尽可能多的应用程序,只要你想单独公开(在我们的例子中是三个独立的应用程序加上原始应用程序实例)

// Create an express instance
const app = express();
const appAdmin = express();
const appClient = express();
const appVendor = express();

之后,您需要安装 vhost 并导入它。然后为每个应用程序指定静态文件夹,您可以分别处理静态文件的服务,而其余部分分别处理对给定子域的请求。

  appAdmin.use(express.static(path.join(__dirname, 'build-admin')));
  appClient.use(express.static(path.join(__dirname, 'build-client')));
  appVendor.use(express.static(path.join(__dirname, 'build-vendor')));

  appAdmin.use((req, res, next) => {
    return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
  });

  appClient.use((req, res, next) => {
    return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
  });

  appVendor.use((req, res, next) => {
    return res.sendFile(path.resolve( __dirname, 'build-vendor' , 'index.html'));
  });

  app.use(vhost('domain.com', appClient));
  app.use(vhost('www.domain.com', appClient));
  app.use(vhost('a.domain.com', appAdmin));
  app.use(vhost('b.domain.com', appVendor));

不要忘记在域的 DNS 注册表中添加所需的子域。例子:

...records
CNAME   vendor  @
CNAME   admin   @