【问题标题】:Deploy app to Heroku with separate frontend/backend servers使用单独的前端/后端服务器将应用程序部署到 Heroku
【发布时间】:2017-12-26 23:54:14
【问题描述】:

我目前正在尝试将应用程序部署到单个 Heroku dyno,它不使用 create-react-app,但有一个用于 webpack 的快速服务器和一个 rails API 后端。

我在将我的请求代理到 API 时遇到问题(但在本地工作正常),这是 Heroku 日志中的错误:

2017-12-03T16:00:18.436271+00:00 app[web.1]: Error: connect ECONNREFUSED 127.0.0.1:3005
2017-12-03T16:00:18.436308+00:00 app[web.1]:     at Object.exports._errnoException (util.js:1018:11)
2017-12-03T16:00:18.436309+00:00 app[web.1]:     at exports._exceptionWithHostPort (util.js:1041:20)
2017-12-03T16:00:18.436311+00:00 app[web.1]:     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1090:14)

我确保将 buildpacks 用于 node 和 rails 作为described here

以下是相关代码:

过程文件

web: npm run start:prod
api: bundle exec rails server --port=3005 --environment=production -b 127.0.0.1

package.json

{
  "name": "foo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "proxy": "http://127.0.0.1:3005/",
  "engines": {
    "node": "6.10.2",
    "yarn": "0.24.5",
    "npm": "5.5.1"
  },
  "scripts": {
    "start": "NODE_ENV=development node server",
    "start:prod": "yarn run build && NODE_ENV=production node server",
    "build": "NODE_ENV=production webpack -p --config ./webpack.prod.js --progress --colors --display-error-details"
  },

server.js

const express = require('express');
const proxy = require('express-http-proxy');

const app = express();

const port = process.env.PORT || 3000;
const path = require('path')
const webpack = require('webpack')

const proxyHost = '127.0.0.1';
const proxyPort = '3005';

app.use('/api', proxy(`${proxyHost}:${proxyPort}`));

const isProd = process.env.NODE_ENV === 'production'

let config

if (isProd) {
  config = require('./webpack.prod.js')
} else {
  config = require('./webpack.dev.js')
}

const publicPath = config.output.publicPath || '/';
const outputPath = config.output.path || path.resolve(process.cwd(), 'dist');

if (!isProd) {
  console.log('Development env detected: Initializing hot reloading')
  const webpackDevMiddleware = require('webpack-dev-middleware')
  const webpackHotMiddleware = require('webpack-hot-middleware')
  const compiler = webpack(config)

  app.use(webpackHotMiddleware(compiler, {
    log: console.log,
    path: '/__webpack_hmr'
  }))

  app.use(webpackDevMiddleware(compiler, {
    entry: config.entry,
    publicPath: config.output.publicPath,
    stats: {
      colors: true
    }
  }))

  app.use('*', function (req, res, next) {
    const filename = path.join(compiler.outputPath, 'index.html')
    compiler.outputFileSystem.readFile(filename, (err, result) => {
      if (err) {
        return next(err)
      }
      res.set('content-type', 'text/html')
      res.send(result)
      res.end()
    })
  })

} else {
  app.use(publicPath, express.static(outputPath));
  app.get('*', (req, res) => res.sendFile(path.resolve(outputPath, 'index.html')));
}

app.listen(port, (err) => {
  if (err) {
    console.log(err.message)
  } else {
    console.log(`Server Started at port ${port}`);
  }
});

任何帮助将不胜感激!

编辑解决方案

所以我能够根据下面接受的答案找到解决方案,但我想我会更新帖子以提供具体细节。

正如答案中所指出的,Heroku 似乎在您的 Procfile 中为每个进程使用不同的测功机,这就是前端/后端服务器最初无法相互通信的原因。

为了避免这种情况,我只是创建了一个虚拟 procfile,它使用 foreman 来初始化真正的 procfile:

Procfile(Heroku 使用的虚拟文件)

web: foreman start -f StartProcfile

StartProcfile(实际进程)

web: npm run start:prod
api: bundle exec rails server --port=3005 --environment=production

应该注意的是,在我的情况下,我遇到了超过 dyno 内存上限并且需要超过 60 秒才能绑定到分配的 heroku 端口的其他问题。原来是因为我在 web 过程中包含了构建步骤,而我应该在 package.json 中使用 postinstall 钩子。

package.json

  "scripts": {
    "start": "NODE_ENV=development node server",
    "start:prod": "NODE_ENV=production node server --optimize_for_size --max_old_space_size=460 --gc_interval=100",
    "build": "NODE_ENV=production webpack -p --config ./webpack.prod.js --progress --colors --display-error-details",
    "postinstall": "npm run build"
  },

【问题讨论】:

  • 嗨,克里斯,我很好奇,是什么让你决定使用两个框架而不是一个?什么不是全部都在 RoR 上或全部在节点上?你介意分享吗?
  • RoR 主要是一个后端框架。它非常适合静态网站,但不适用于 React 等动态/单页面应用程序。我本可以在后端使用 node,但我对 RoR 更满意,所以我决定坚持下去。
  • 谢谢。我喜欢 Ruby,但在 4.0 发布时我离开了 RoR 以选择其他选项……我注意到我只喜欢 ActiveRecord 和迁移部分,所以我取消了额外的层并在 Ruby 领域选择了更轻的选项。从未回头,但我仍然不时想知道为什么人们坚持 RoR。

标签: ruby-on-rails node.js heroku


【解决方案1】:

Procfile 中的每一行最终都在一个单独的测功机中运行。如果您需要两个进程在同一个测功机上运行(在本例中为 web),那么您需要重新定义 web 以调用类似于启动节点服务器然后启动 rails 服务器的 shell 脚本,或者让节点启动过程启动 Rails 服务器。

完全披露,我从未真正做过你正在尝试的事情。即使在进行了上述更改后,将 rails API 服务器绑定到端口 3005 也可能无法正常工作。但是,可以肯定的是,web 进程中的127.0.0.1 永远不会是api 进程中的127.0.0.1,因为它们将始终在不同的测功机上运行。希望这些信息有所帮助。

【讨论】:

  • 我可以做类似web: npm run start:prod && bundle exec rails server --port=3005 --environment=production -b 127.0.0.1的事情吗?
  • 我从未尝试过。但如果该命令在 unix 终端本地运行,它应该在 Heroku 上运行。
  • 那么您是否设法在 Heroku 上手动绑定端口?我在使用 Nuxt.js 和 Django 时遇到问题,这与您的情况相似,想知道我是否可以在不使用工头的情况下在一行中使用 &&
猜你喜欢
  • 2020-11-16
  • 2020-05-29
  • 2020-03-13
  • 2021-10-12
  • 2021-11-12
  • 2020-05-20
  • 2019-10-31
  • 2021-05-13
  • 1970-01-01
相关资源
最近更新 更多