Phusion Passenger 错误:http.Server.listen() 被多次调用

mic*_*elb 5 passenger nginx http-proxy node.js

我想使用 nginx 在 phusion guest 上执行一个简单的 node-http-proxy 示例。您可以在https://github.com/nodejitsu/node-http-proxy上找到此示例代码。

var http = require('http'),
httpProxy = require('http-proxy');
//
// Create your proxy server
//
httpProxy.createServer(9000, 'localhost').listen(8000);

//
// Create your target server
//
http.createServer(function (req, res) {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
  res.end();
}).listen(9000);
Run Code Online (Sandbox Code Playgroud)

如果我执行这段代码,我会收到以下错误。

App 28096 stderr: /usr/share/passenger/helper-scripts/node-loader.js:157
App 28096 stderr:       throw new Error("http.Server.listen() was called more than once, which " +
App 28096 stderr:             ^
App 28096 stderr: Error: http.Server.listen() was called more than once, which is not allowed because Phusion Passenger is in auto-install mode. This means that the first http.Server object for which listen() is called, is automatically installed as the Phusion Passenger request handler. If you want to create and listen on multiple http.Server object then you should disable auto-install mode.
Run Code Online (Sandbox Code Playgroud)

比我在谷歌群组https://groups.google.com/forum/#!topic/phusion-passenger/sZ4SjU8ypwc上找到一篇帖子并添加

PhusionPassenger.configure({ autoInstall: false });
Run Code Online (Sandbox Code Playgroud)

在我第一次调用“createServer(...).listen(port)”之前。

下一步是将监听方法的端口参数值替换为“passenger”值。但我没有成功。有人设法让它运行吗?

---我的解决方案---

感谢 Hongli 的建议“接下来,您需要修改一个(且只有一个)调用......”。这解决了我的问题。

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

if (typeof(PhusionPassenger) != 'undefined') {
  PhusionPassenger.configure({ autoInstall: false });
}

httpProxy.createServer(9000, 'localhost').listen('passenger');

var target_server = http.createServer(function (req, res) {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
  res.end();
}).listen(9000);
Run Code Online (Sandbox Code Playgroud)

Hon*_*gli 5

2015 年 7 月 28 日更新:此答案现已合并到官方 Passenger 文档中。最新答案请参阅https://www.phusionpassenger.com/library/indepth/nodejs/reverse_port_binding.html 。


Phusion Passenger 作者在这里。首先我来解释一下为什么会出现这个错误。

正如Node.js 教程中所解释的,Phusion Passenger通过挂钩来反转端口绑定http.Server.listen()。如果有多个listen(),则 Passenger 不知道使用哪个 http.Server 对象来接收请求,因此会抛出此错误。

为了解决这个问题,你需要告诉 Passenger “我想明确指定使用哪个 http.Server 来接收请求”。这是分两步完成的。首先,您必须在程序中尽早调用以下代码:

if (typeof(PhusionPassenger) != 'undefined') {
    PhusionPassenger.configure({ autoInstall: false });
}
Run Code Online (Sandbox Code Playgroud)

接下来,您需要修改 的一次(且仅有一次)调用http.Server.listen(),并使其传递'passenger's 参数:

server.listen('passenger');
Run Code Online (Sandbox Code Playgroud)

如果 Passenger 发现您有多个listen('passenger')电话,它会投诉。你只能拥有一个。

从 Phusion Passenger 4.0.52 开始,您还可以'/passenger'作为参数传递。这是为了 Hapi.js 支持(见下文)。

Express.js 示例

这是一个利用 Express 框架的完整示例。您必须转接'passenger'Express 的listen()电话。

if (typeof(PhusionPassenger) != 'undefined') {
    PhusionPassenger.configure({ autoInstall: false });
}

var express = require('express');
var app = express();
app.get('/', function(req, res){
    var body = 'Hello World';
    res.setHeader('Content-Type', 'text/plain');
    res.setHeader('Content-Length', body.length);
    res.end(body);
});

if (typeof(PhusionPassenger) != 'undefined') {
    app.listen('passenger');
} else {
    app.listen(3000);
}
Run Code Online (Sandbox Code Playgroud)

Hapi.js 示例

使用 Hapi.js 时,您必须将'/passenger'(而不是'passenger') 传递给 Hapi 的服务器构造函数。这将导致 Hapi 尝试侦听 Unix 域套接字,从而允许 Phusion Passenger 的覆盖启动。如果您不传递该初始斜杠,则 Hapi 将尝试将参数视为 TCP/IP 域名,并且 Hapi 将尝试将参数视为 TCP/IP 域名。因错误而失败。

if (typeof(PhusionPassenger) != 'undefined') {
    PhusionPassenger.configure({ autoInstall: false });
}

var Hapi = require('hapi');
var server;

if (typeof(PhusionPassenger) != 'undefined') {
    // Requires Phusion Passenger >= 4.0.52!
    server = new Hapi.Server('/passenger');
} else {
    server = new Hapi.Server('localhost', 3000);
}

server.route({
    method: 'GET',
    path: '/hello',
    handler: function (request, reply) {
        reply('hello world');
    }
});

server.start();
Run Code Online (Sandbox Code Playgroud)