2012-05-28 8 views
15

Ich habe einen Root-Server, auf dem mehrere node.js-Projekte laufen. Sie sollen separat in ihren eigenen Prozessen und Verzeichnissen laufen. Betrachten Sie diese Dateistruktur:Einen Port unter mehreren node.js-HTTP-Prozessen teilen

/home 
+-- /node 
    +-- /someProject  | www.some-project.com 
    | +-- index.js 
    | +-- anotherFile.img 
    | +-- ... 
    +-- /anotherProject | www.another-project.com 
    | +-- /stuff 
    | +-- index.js 
    | +-- ... 
    +-- /myWebsite  | www.my-website.com 
    | +-- /static 
    | +-- index.js 
    | +-- ... 
    +-- ...    | ... 

Jeder index.js als individueller Prozess mit seinem cwd Satz zu seinem übergeordneten Ordner gestartet werden soll (someProject, anotherProject, etc.).

Denken Sie an vHosts. Jedes Projekt startet einen Webserver, der auf seine eigene Domain hört. Und da ist das Problem. Nur ein Skript kann starten, da alle versuchen, an Port 80 zu binden. Ich habe in die node.js-API gegraben und nach einer möglichen Lösung gesucht: child_process.fork().

Leider funktioniert das nicht sehr gut. Wenn ich versuche, eine Server-Instanz an den Master-Prozess zu senden (um später eine Anfrage zu senden) oder ein Objekt, bestehend aus request und response vom Master zum salve bekomme ich Fehler. Dies liegt daran, dass node.js intern versucht, diese erweiterten Objekte in eine JSON-Zeichenfolge zu konvertieren und sie dann in ihre ursprüngliche Form zurückkonvertiert. Dadurch verlieren alle Objekte ihren Bezug und ihre Funktionalität.

seccond Ansatz child.js

var http = require("http"); 

var server = http.createServer(function(req, res) { 
    // stuff... 
}); 
server.listen(80); 

process.send(server); // Nope 

Erster Ansatz master.js

var http = require("http"), 
    cp = require("child_process"); 

var child = cp.fork("/home/node/someProject/index.js", [], { env: "/home/node/someProject" }); 

var router = http.createServer(function(req, res) { 
    // domaincheck, etc... 
    child.send({ request: req, response: res }); // Nope 
}); 
router.listen(80); 

Also das ist eine Sackgasse. Aber hey! Node.js bietet einige Arten von Handles, die sendbar sind. Hier ist ein Beispiel aus der Dokumentation:

master.js

var server = require('net').createServer(); 
var child = require('child_process').fork(__dirname + '/child.js'); 
// Open up the server object and send the handle. 
server.listen(1337, function() { 
    child.send({ server: true }, server._handle); 
}); 

child.js

process.on('message', function(m, serverHandle) { 
    if (serverHandle) { 
    var server = require('net').createServer(); 
    server.listen(serverHandle); 
    } 
}); 

hier direkt das Kind auf den Master-Server lauscht. Es gibt also keinen Domänencheck dazwischen. Also, hier ist eine Sackgasse.

Ich dachte auch über Cluster, aber das verwendet die gleiche Technologie wie der Griff und hat daher die gleichen Einschränkungen.

Also ... gibt es irgendwelche guten Ideen?

Was ich derzeit mache ist eher hack-ish. Ich habe ein Paket namens distroy gemacht. Es bindet an Port 80 und proxifiziert intern alle Anfragen an Unix-Domain-Socket-Pfade wie /tmp/distroy/http/www.example.com, auf denen die einzelnen Apps zuhören. Dies funktioniert auch (irgendwie) für HTTPS (siehe meine Frage auf SNI). Das verbleibende Problem ist, dass die ursprüngliche IP-Adresse verloren geht, da es jetzt immer 127.0.0.1 ist. Ich denke, ich kann das umgehen, indem ich die net.Server monkeypatching, so dass ich die IP-Adresse vor dem Öffnen der Verbindung übertragen kann.

+1

Wenn jemand eine "besser passende" Lösung für dieses Problem findet, werde ich seine Antwort als die richtige markieren. – buschtoens

+0

Ich arbeite derzeit an etwas, das dieses Problem lösen sollte ... – buschtoens

+0

Jeder weiß, wie dies beim Ausführen von Knoten innerhalb von IIS zu tun? –

Antwort

1

Persönlich würde ich nur alle auf dedizierte Ports oder vorzugsweise Sockets hören und dann alles hinter einem dedizierten Router-Skript oder Nginx stecken. Es ist der einfachste Ansatz IMO.

+0

Ich mag nur die Idee, ein leichtes node.js-Skript zu haben, das die Anfrage intern umschreibt. Leider ist das im Moment nicht möglich und ich bleibe bei den Unix Sockets. – buschtoens

+1

Ich bin wirklich verwirrt, warum meine Antwort 0/2 geht, wenn die Empfehlung von almypal genau die gleiche ist (einfach alles auf verschiedenen Ports belassen und einen separaten Router verwenden) und geht 6/0. Ich interessiere mich nicht wirklich für ein tiefes Level, aber es ist neugierig. – Chuck

9

Wenn Sie an einer Lösung von node.js interessiert sind, lesen Sie bouncy, einen Websocket und https-fähigen HTTP-Router Proxy/Load Balancer in node.js.

Definieren Sie Ihre routes.json wie

{ 
     "beep.example.com" : 8000, 
     "boop.example.com" : 8001 
} 

und dann federnd

bouncy routes.json 80 
+0

bouncy ist fast das gleiche wie [http-proxy] (https://github.com/nodejitsu/node-http-proxy). Was mich an dieser Art von Lösung ärgert, ist die Tatsache, dass der Projektserver sich an einen anderen Port bindet, den er eigentlich nicht benutzt, da er an Port 80 binden sollte. – buschtoens

+0

+1 auf http-Proxy - das verwende ich – bryanmac

0

Für connect Middleware laufen gibt es vhost Erweiterung. Vielleicht könnten Sie einige ihrer Konzepte kopieren.

+0

Connect's 'vhost' macht das grundsätzlich:' server.emit ('request', req, res); '. Das habe ich schon probiert. Sie müssen die Serverinstanz des untergeordneten Prozesses abrufen, um Ereignisse für sie ausgeben zu können. Da node.js diese Instanz intern beschriftet, gehen alle Referenzen verloren und ich kann dort keine Ereignisse ausgeben. – buschtoens