NodeJS HTTP - 如何在非80端口上监听?

10

我在Windows上运行XAMPP来托管一个在80端口上运行的Apache服务器。现在我正在尝试让一个NodeJS脚本在后台运行,但问题是它只能监听80端口。如果这样做,一切都按照预期工作,但我不能同时运行Apache,因为Apache具有优先权并仅提供我的网站服务。NodeJS脚本甚至无法开始监听。

我的问题是:如何切换NodeJS脚本的监听端口(具体端口并不重要),以便Apache仍然可以在80端口上运行,我可以从世界各地访问NodeJS脚本。

NodeJS代码的一部分:

const http = require('http');

const port = 8080;
const host = '0.0.0.0';




server = http.createServer( function(req, res) {
    if (req.method == 'POST') {
        var body = '';
        req.on('data', function (data) {
            body += data;
            doStuff(body);
        });
        res.writeHead(200, {'Content-Type': 'text'});
        res.end('received request successfully');
    }
    else {
        res.writeHead(405, {'Content-Type': 'text'});
        res.end('not allowed method ' + req.method + ', try again with GET or POST');
    }

})

server.listen(port, null, function(error){
  if(!!error){
    console.log("\x1b[41m%s\x1b[0m", "error while initializing listener on port " + port + ": " + error);
   }
   else{
    console.log("\x1b[32m%s\x1b[0m", "started listener at 'http://" + host + ':' + port + "'");}
 });

更多信息请参见我的其他问题,该问题被标记为重复。


1
你需要为此设置反向代理。去谷歌一下吧。 - Ankit Agarwal
@AnkitAgarwal 谢谢,我会查一下的。 - Sv443
当您更改端口时,您遇到了什么错误? - willascend
@willascend 很抱歉回复晚了。我没有收到任何错误信息,程序启动正常,只是无法获取任何数据。 - Sv443
1
明白了。这表明服务器很可能在指定的端口上运行。听起来问题是在没有在URL中使用端口访问节点服务器。请尝试使用反向代理使其正常工作。另外,提供有关如何设置Apache服务器以及如何从外部访问节点服务器的其他信息可能也会有所帮助。 - willascend
6个回答

6
看了你的其他问题,这个问题被标记为与此重复,你在那里提供了一些额外的信息,这可能有助于阐明你需要什么。具体来说,你提到了以下内容:
“我想使用NodeJS托管多个HTTP服务器,它们都会接收和发送HTTP请求。同时,我想让Apache运行,占用端口80。如果我禁用Apache并让NodeJS在端口80上运行,它将工作,但我不能让它们同时运行。”
“这个脚本将在本地的8081端口运行和接收请求,但是即使在使用路由器转发端口后,我似乎也无法通过Internet向其发送AJAX请求:”
我认为@ankit-agarwal可能是正确的,你需要设置反向代理来将流量转发到不同的后端。假设你有一个面向外部的IP地址,你应该能够使用它们监听的端口访问每个后端。例如,如果你的机器的公共IP地址是100.120.110.43:
+---------+------+-------------------------------------+
| Backend | Port |             Web Address             |
+=========+======+=====================================+
| Apache  |   80 | 100.120.110.43 or 100.120.110.43:80 |
| Node1   | 8080 | 100.120.110.43:8080                 |
| Node2   | 8081 | 100.120.110.43:8081                 |
+---------+------+-------------------------------------+

如果你希望不用指定端口就能访问每个后端,你必须有一些方法来告诉你的内部网络根据请求选择哪个后端进行服务。其中一种方式是使用基于路径的路由,通过设置反向代理将流量路由到不同的后端,基于 url 中的路径来实现。你没有发布你的 Apache 配置,但你可以使用当前的 Apache 服务器来处理此问题,使用以下类似的 ProxyPassProxyPassReverse 指令:
ProxyPass "/node1"  "http://100.120.110.43:8080/"
ProxyPassReverse "/node1"  "http://100.120.110.43:8080/"

ProxyPass "/node2"  "http://100.120.110.43:8081/"
ProxyPassReverse "/node2"  "http://100.120.110.43:8081/"

使用反向代理的好处是您不必将节点后端暴露给公众。假设您还没有这样做,它们只能从内部网络的0.0.0.0:port访问。
Listen 80
<VirtualHost *:80>
    DocumentRoot /www/apache
    ServerName www.apachefrontend.com
    ProxyRequests off
    ProxyPass /node1  http://0.0.0.0:8080/
    ProxyPassReverse /node1  http://0.0.0.0:8080/
    ProxyPass /node2  http://0.0.0.0:8081/
    ProxyPassReverse /node2  http://0.0.0.0:8081/
</VirtualHost>

你还可以指向只有你自己可以访问的不同主机/IP地址。
最后,如果你有不同的 DNS 记录来指向不同的后端,你也可以使用 VirtualHost 和 ServerName。
Listen 80
<VirtualHost *:80>
    DocumentRoot /www/apache
    ServerName www.apachefrontend.com
</VirtualHost>
<VirtualHost *:80>
    ServerName www.nodebackend1.com
    ProxyRequests off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    <Location />
        ProxyPass /  http://0.0.0.0:8080/
        ProxyPassReverse /  http://0.0.0.0:8080/
    </Location>
</VirtualHost>
<VirtualHost *:80>
    ServerName www.nodebackend2.com
    ProxyRequests off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    <Location />
        ProxyPass /  http://0.0.0.0:8081/
        ProxyPassReverse /  http://0.0.0.0:8081/
    </Location>
</VirtualHost>

若要启用上述任何内容,您需要在Apache中启用mod_proxymod_proxy_http
这些可能不是最强大的示例,并且我没有对其进行测试,但它们应该说明这个想法。您可以在此了解更多信息:这里

谢谢你的回答!我现在正在工作,无法测试它,但我会确保今天晚些时候尝试一下。 - Sv443
我尝试按照您说的做,并将第一部分代码复制到httpd.conf中(我删除了Listen 80,因为我已经有它了)。此外,我取消注释了mod_proxy和mod_proxy_http。但是重新启动服务器导致Apache无法启动。 这是我的httpd.conf:https://pastebin.com/NHDzsLeV - Sv443
它没有启动是因为我没有将 DocumentRoot 用引号括起来。现在,当我发 POST 请求时,它会给我一个404错误,这不是一个很大的问题,但现在 Apache 仍然接受请求,而不是将其重定向到0.0.0.0:8081。 - Sv443
经过一番尝试,我终于用你提供的第一个代码片段让它正常工作了。问题在于我配置请求时出错了,并且我的httpd.conf中有一个多余的、第二个ServerName。 非常感谢! - Sv443

0

只需将您的 node.js 服务器端口更改为以下内容:

var server = app.listen(8080, function() {
    console.log('Ready on port %d', server.address().port);
});

其中8080是Node.js服务器的新端口。


那不起作用,即使我在路由器上打开了那个端口。 - Sv443
你能展示一下你是如何设置node.js服务器的吗?请将你的代码嵌入到问题中。 - Hendro Febrian
我添加了代码片段。但由于它是用于我的工作,所以我不能发布全部内容。 - Sv443
将端口更改为8000。 - Hendro Febrian

0

看起来你的 8080 端口上已经有东西在运行了。只需要切换到另一个端口即可,比如 7000。确保所有请求调用 Node.js 应用程序时都像这样。

localhost:7000 // Normal we run at port 80 url simply localhost without port

该端口上没有运行任何程序。我已经通过netstat进行了检查。我还尝试了8081端口。 - Sv443

0

我并没有完全理解你所说的“没有任何响应”,因为我运行了同样的代码,它在我这里正常工作。

我只注意到这里有些问题(我在注释中留了一个备忘录给你)

server = http.createServer( function(req, res) {
    if (req.method == 'POST') {
        var body = '';
        req.on('data', function (data) {
            body += data;
            doStuff(body); //you haven't defined doStuff so you will end up with a error message on this line, but you sever will still run fine
        });
        res.writeHead(200, {'Content-Type': 'text'});
        res.end('received request successfully'); 
    }
    else {
        res.writeHead(405, {'Content-Type': 'text'});
        res.end('not allowed method ' + req.method + ', try again with GET or POST');
    }

})

Postman image

在运行您的POST请求时,请不要忘记在body区域中添加"",选择raw,然后选择JSON(application/json)。这样应该可以正常运行,除非您可能会遇到如下所示的reference error,但您仍然应该能够获得received request successfully的响应。

错误

            doStuff(body);
            ^

ReferenceError: doStuff is not defined

确保你正在做同样的事情,并让我们知道你的问题是否已解决。


doStuff(body); 只是一个占位符。实际上我有另一个函数。服务器从未收到任何请求,也没有显示任何活动。 - Sv443
此外,迟一年的跟进:localhost 从未是问题所在。我想让它可以通过互联网访问。 - Sv443
太好了!那么我就假设一切都对你来说运作正常。 - antzshrek
在问题提出时它并没有正常工作,但是我通过使用反向代理解决了这个问题。 - Sv443
好的,那么这是否意味着你现在仍然存在同样的问题? - antzshrek
我按照willascend的指示(被接受的答案)操作,几个小时内就使它正常工作了。 - Sv443

0

这与在共享主机中使用NodeJs的情况相同。我已经写了一篇关于它的博客文章在这里

让我给你摘录一段。

  1. 8080 端口上运行 NodeJS 服务器。

  2. 现在,假设您的 Apache 服务于 http://example.com,请在您的 public_htmlwww 中创建一个文件夹。假设名称为 server。因此,您的新文件夹路径为 http://example.com/server

  3. 在服务器文件夹中创建一个 .htaccess 文件
  4. 添加以下行:

    RewriteEngine On
    RewriteRule ^$ http://127.0.0.1:8080/ [P,L] #which is your node server ip:port
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ http://127.0.0.1:8080/$1 [P,L] #same ip:port
    

这将把所有来自于 http://example.com/server 的请求重定向到你的 Node 服务器。


这让我得到了一个500内部服务器错误。 - Sv443
你能否检查一下请求是否真的到达了Node.js服务器?因为我有相同的设置,而且它对我来说也运作正常。 - Aritra Chakraborty
不是的。我只是收到了一个500错误。 - Sv443
你也添加了注释吗?例如#这是...#相同IP。请将其删除并尝试。我刚在本地设置中测试过。 - Aritra Chakraborty
这可悲的是没有改变任何事情。 - Sv443
不知道啊,我有一个本地的Apache并且做了完全相同的事情。使用.htaccess和你的Node.js代码。它可以正常工作。收到请求成功。 - Aritra Chakraborty

0
如果我想在同一端口使用Apache和Nodejs: npm http-proxy-middleware 1. 将Apache端口设置为81 [apache dir]/conf/httpd.conf

~59: Listen 81

2. 设置nodejs APP端口=3050

server.listen(3050); // 在Linux上,端口<1000需要root权限

3. 使用第三方代理APP(http-proxy-middleware)
  // https://www.npmjs.com/package/http-proxy-middleware
  var express = require('express');
  var proxy = require('http-proxy-middleware');

  // proxy middleware options
  var options = {
      target: 'http://localhost:81', // target host ROOT
      changeOrigin: true, // needed for virtual hosted sites
      ws: true, // proxy websockets
      pathRewrite: {
          // '^/api/old-path' : '/api/new-path',     // rewrite path
          // '^/api/remove/path' : '/path'           // remove base path        
      },
      router: {
          // Examples:
          // when request.headers.host == 'dev.localhost:3000',
          // override target 'http://www.example.org' to 'http://localhost:8000'
          // 'dev.localhost:3000' : 'http://localhost:8000',
          // 'localhost:9000': 'localhost:9002/sub',                 
          // '/sub': 'http://localhost:9002',

          'localhost': 'http://localhost:81',         //Root to Apache
          'sub.localhost': 'http://localhost:3050',  // internal
          'sub.mydomain.com': 'http://localhost:3050', //external
      },
  };

  // create the proxy (without context)
  // var proxy_wp = proxy(options_wp);
  var proxy_node = proxy(options);

  // mount `exampleProxy` in web server
  var app = express();
  app.use(proxy_node);
  app.listen(80);

然后:

  1. localhost:80 - 是 Apache 网站
  2. sub.localhost:80 - Node
  3. localhost:80/sub - 如果你设置了,也是 Node

对于任务运行器,我使用npm PM2


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