Heroku + node.js:我有一个使用多个端口的服务器。如何让Heroku分配它们?

42

嗯,我会尽力更清晰地说明:

在我编写的node.js应用程序服务器中,我有多个端口的内部代理:

  • 我在8080端口上有我的rest api
  • 我在3000端口上有我的推送服务器和聊天功能

我使用npm包subdomain-router进行内部路由到端口,并在“前端”公开子域名以代理回这些端口。
代码演示:<some-app>显然不是真实的应用程序名称)

require('subdomain-router')
({
  host: '<some-app>.herokuapp.com',
  subdomains:
  {
    '': 8080,   // <some-app>.herokuapp.com <=> ::8080   --WORKS--
    'api': 8080,  // api.<some-app>.herokuapp.com <=> ::8080
    'chat': 3000, // chat.<some-app>.herokuapp.com <=> ::3000
    'push': 3000  // push.<some-app>.herokuapp.com <=> ::3000
  }
}).listen(process.env.PORT || 5000);
API能正常工作,但我只能通过<some-app>.herokuapp.com来访问它,而不能通过<some-app>.herokuapp.com:8080来访问。同时,我无法访问子域名。当尝试访问api.<some-app>.herokuapp.com时,我会从heroku得到No such app错误页面。
TL;DR:可以访问<some-app>.herokuapp.com(将其重定向到我的API的/v1路径),但无法访问<some-app>.herokuapp.com:8080<some-app>.herokuapp.com:3000chat.<some-app>.herokuapp.com。在URL中指定端口时(如此:<some-app>.herokuapp.com:8080),我在浏览器(Google Chrome)中得到以下错误:ERR_CONNECTION_REFUSED。我猜测这可能与在heroku中开放端口有关,但我不知道如何做(已经尝试过谷歌搜索了)。这并不解释为什么我无法访问子域名。希望有人能解决这个问题。我是新手,很沮丧。谢谢!Amit
4个回答

35

经过一些调查,我发现在Heroku中打开端口是被禁用的并且不允许使用。

唯一的方法是使用子域名,然后在应用程序中使用代理模块(如我使用的subdomain-router)。

但是 - Heroku 不允许您在其域上创建子域名,这意味着your-app.herokuapp.com是固定的,不能具有子域名。
在Heroku手册中,他们要求您拥有自己的域名和DNS提供商才能执行此操作,通过在域设置的DNS表中创建一个A-别名(CNAME),该别名将指向您的应用程序herokuapp域,并使用命令heroku domains:add将您的域添加到允许的来源列表。

您可以在此处阅读更多信息。它提供了您需要的所有信息。

希望对您有所帮助。


2
是的,你只有那一个端口,但你可以通过它来服务于你的WebSockets以及HTTP请求。 - Anthony
@Antoine,如何在同一端口处理HTTP请求和TCP(websocket)消息? - vin
@Antoine 我和vin在一起 - 这怎么工作?我也遇到了同样的问题,但是不得不绕过所有这些工作才能处理一些HTTP请求,真的感觉很烦人... - Stefan Falk

13

我知道这是一个旧帖,但我想提供一个最新的回复供参考和未来使用:

如果你正在使用socket-io,则绑定到相同的端口很容易。其他websocket库应该有类似的方法(来源于https://github.com/socketio/socket.io#how-to-use):

与Express一起使用 从3.0开始,express应用程序已成为您传递给http或http Server实例的请求处理程序函数。您需要将Server传递给socket.io,而不是express应用程序函数。还请确保在服务器上调用.listen,而不是在应用程序上。

const app = require('express')();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
io.on('connection', () => { /* … */ });
server.listen(3000);

现在,您将通过单个端口流传http和ws流量(如果Heroku分别路由http / tcp,则您的WebSockets将无法正常工作)。

我喜欢这种方法是因为它可以实现环境平等和测试,即无需设置子域名或端口路由。


4

今天我也了解到了这一点,如果你在Heroku上的某个端口运行一个服务,你仍然可以在本地访问它。这对上面用户的问题并没有用,但它确实解决了我的问题,也引发了我提出这个问题。


0

你可以创建一个代理服务器来访问任何本地端口。

说明:

Heroku 将你的应用程序进行了 Docker 化,既是为了安全措施,也是为了能够在一台机器上部署多个应用程序。这要求他们自行管理暴露的端口(请注意,你无法更改暴露的端口,每个应用程序只有一个)。

因此,如果你想公开多个服务器,则需要有一个映射服务器将请求代理到不同的服务器。

NextJS + NodeJS 示例:

我在端口 4000 上运行我的 NodeJS 服务器(未公开),而我的 NextJS 应用程序侦听 Heroku 的公开端口 PORT=$PORT npm run --prefix ./next/ start

NextJS 允许你重写请求,所以我可以将任何请求指向内部端口,以下是我的next.config.js中的代码:

  async rewrites() {
    return {
      beforeFiles: [
        {
          source: '/health',
          destination: 'http://localhost:4000/health'
        },
        {
          source: '/v1/:path',
          destination: 'http://localhost:4000/v1/:path'
        }
      ],
      fallback: [
        {
          source: '/:path*',
          destination: 'http://localhost:4000/:path*'
        }
      ]
    };
  }

你也可以反过来做,即让你的API服务器监听暴露的端口,并将任何请求代理到你的内部端口之一。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接