如何使用 Restify 在同一个端口上运行多个 Node 应用程序?

Posted

技术标签:

【中文标题】如何使用 Restify 在同一个端口上运行多个 Node 应用程序?【英文标题】:How to run multitple Node apps on the same port using Restify? 【发布时间】:2016-07-08 10:34:23 【问题描述】:

我需要在同一个端口上运行多个 Node 应用程序。我发现我可以使用一个端口运行多个节点应用程序,这要归功于这个 SO 问题Running multiple Node (Express) apps on same port 但它可能对我不起作用。除非我在某处做错了什么,否则我会使用 Restify。

我已经在 this 一个端口上运行了 "app1",使用的是使用 Restify 构建的 PM2。我制作了另一个应用“app2”。路径如下:

/var/www/app1
/var/www/app2

每个应用都有这样的共同路线:

app.get('/', func...);
app.get('/about', func...);
app.post('/foo', func...);
app.post('/bar', func...);

我已将 "app1" 的最后几行代码设置为:exports.app = app 而不是 app.listen(8080, function() ... );

并且,app

var app = restify.createServer(
    name: 'app1'
);

“app2”也一样...

我的main.js 文件(保存在/var/www/)也是基于Restify 构建的:

main
 .use('/app`', require('./app1/index').app)
.listen(8080);

main 在哪里

var main = restify.createServer(
    name: 'main'
);

但是当我输入 node main.js 时出现这样的错误(我还没有尝试使用 PM2):

/var/www/node_modules/restify/node_modules/assert-plus/assert.js:45
                    throw new assert.AssertionError(
                          ^
AssertionError: handler (function) is required
    at process (/var/www/node_modules/restify/lib/server.js:76:24)
    at argumentsToChain (/var/www/node_modules/restify/lib/server.js:84:13)
    at Server.use (/var/www/node_modules/restify/lib/server.js:625:6)
    at Object.<anonymous> (/var/www/main.js:47:8)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)

注意: 我已经关闭了在 PM2 下运行的所有应用。任何端口上都没有运行节点应用程序。

【问题讨论】:

你不能......但是你可以在多核系统中运行同一个应用的多个实例......! app.use() 是特定于 express 的,不能用于将请求转发到除另一个 express“应用程序”之外的任何东西。请参阅下面的答案,了解支持异构服务器的唯一方法。 【参考方案1】:

有效地做到这一点的唯一方法是运行一个配置为在单个端口上响应请求的 HTTP 代理,并根据 URL 模式将它们传递给在其他端口上运行的服务器,一个简单的示例可以在 @ 987654321@.

本质上,您公开可见的代理服务器在端口 80 上运行,而您运行其他服务器来处理特定请求。

例如,如果您运行三台 HTTP 服务器,一台作为转发代理,两台用于特定功能,例如:

80 端口上的代理 server2 在端口 8080 上用于匹配正则表达式的请求:/^\/first(?:\/.*)?$/ 端口 8081 上的 server3 用于匹配正则表达式的请求:/^\/second(?:\/.*)?$/

唯一具有公共连接的服务器是您的代理。

当代理接收到/first/first/index.html 的请求时,它会将请求转发给server2,server2 返回一个结果文档,然后代理将其发回给原始请求者。

当它收到/second/foo/bar/page.html 的请求时,它会执行相同的操作,但使用 server3 来生成结果。

http-proxy 是该策略的一个实现,它使用http-proxy-rules 插件来处理和转发基于 URL 模式的请求。

更新

为了清楚起见,我们假设上面的 proxyserver2server3 代表单个节点 HTTP 服务器实例,它们侦听单个 IP 地址但同一台机器上的不同端口。

例子:

var http = require('http'),
    httpProxy = require('http-proxy'),
    HttpProxyRules = require('http-proxy-rules');

// Set up proxy rules instance
//   where 
//     any request for /hostname/app1 will be proxy-ed via SERVER2
//     any request for /hostname/app2 will be proxy-ed via SERVER3
var proxyRules = new HttpProxyRules(
  rules: 
    '.*/app1/': 'http://localhost:8080',  // TO SERVER2
    '.*/app2/': 'http://localhost:8081'   // TO SERVER3
  
);

// Create reverse proxy instance
var proxy = httpProxy.createProxy();

// Create http server on hostname:80 that leverages reverse 
// proxy instance and proxy rules to proxy requests to 
// different one of two target servers
http.createServer(function(req, res)  // PROXY 

  // a match method is exposed on the proxy rules instance
  // to test a request to see if it matches against one 
  // of the specified rules
  var target = proxyRules.match(req);

  if (target) 
    return proxy.web(req, res, 
      target: target
    );
  

  res.writeHead(500,  'Content-Type': 'text/plain' );
  res.end('No rule found for this request');

).listen(80);

// create a new HTTP server on localhost:8080 to process
// requests sent from the proxy
http.createServer(function (req, res)  // SERVER2
  res.writeHead(200,  'Content-Type': 'text/plain' );
  var headers=JSON.stringify(req.headers,true,2);
  res.write('request successfully proxy-ed to SERVER2!' + '\n' + headers);
  res.end();
).listen(8080,'localhost');

// create a new HTTP server on localhost:8081 to process
// requests sent from the proxy
http.createServer(function (req, res)  // SERVER3
  res.writeHead(200,  'Content-Type': 'text/plain' );
  var headers=JSON.stringify(req.headers,true,2);
  res.write('request successfully proxy-ed to SERVER3!' + '\n' + headers);
  res.end();
).listen(8081,'localhost');

使用此设置:

只有代理服务器在外部端口 80 上可用 在端口 8080 和 8081 上运行的服务器在本地计算机上可用 在主机名:80 的代理上收到的与/app1 路径(和后代)匹配的请求将由运行在localhost:8080 上的服务器代理 在主机名:80 的代理上收到的与/app2 路径(和后代)匹配的请求将由运行在localhost:8081 上的服务器提供服务

【讨论】:

感谢您的建议。它通过为 server2 和 server3 提供自己的端口来工作。但是npmjs.com/package/http-proxy-rules 手册显示 server2 和 server3 可以具有相同的端口。我以这种方式尝试过,但没有奏效。我确实需要 server2 和 server3 具有相同的端口,我只是在 rules: '.*/test': 'http://localhost:8080/server2', // Rule (1) '.*/test2/': 'http://localhost:8080/server3/' // Rule (2) , 上监听,然后监听端口 8000。你知道怎么做吗? 抱歉,无论您多么努力,每个端口都不能运行多个侦听器。这是操作系统的 TCP/IP 堆栈的限制,没有办法绕过它。您引用的示例不在同一端口上运行两台服务器。相反,它重定向到由同一服务器在端口 8080 上提供的两个 URL。 嗨@Rob Raisch,感谢您的解释,但这就是我的想法; 同一端口上的同一台服务器。 如何为 2 个节点应用程序使用相同的主机名和端口号(您在答案中命名为 server2 和 server3)?我不明白server2 是如何作为url 的一部分创建的,以及它在http://localhost:8080/server2 中是如何工作的?我知道如果我输入http://localhost:8080/test,它会重定向到http://localhost:8080/server2。但我不知道如何制作http://localhost:8080/server2 url,以便我可以重定向到适当的节点应用程序? .../server2 是目录吗? 也许我还不清楚。每个 IP 地址和 TCP 端口号对不能运行多个侦听器,并且由于主机名 localhost 是服务器主机上“环回”网络接口的 IP 地址 (127.0.0.1) 的简写,您不能127.0.0.1:8080 上运行多个进程。句号。 关于 http-proxy-rules 示例代码,您会注意到,它不是在同一个端口上运行多个服务器,而是描述将请求代理到 同一服务器上的不同目标路径 i> 在localhost:8080 上运行。

以上是关于如何使用 Restify 在同一个端口上运行多个 Node 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 restify 上扩展 socket.io?

如何使用 Node.JS 的 restify 框架解析/读取多个参数

Node.js 使用 socket.io 进行重构

在 Elastic Beanstalk 上运行时如何获取服务器 URL?

如何在多个 HTTPS 端口上运行 Spring Boot HTTPS 服务器

关于在同一端口上运行多个应用程序