ExpressJS服务器 – 如何处理多个域

我在Express上玩弄了一下,我想知道,“最正确”的方法是处理链接到同一台服务器的多个域。

让我们假设我们有

  • foo.com
  • bar.net
  • baz.com

全部指向111.222.333.444 。 该机器正在使用Express运行NodeJS。 我目前的解决scheme如下所示:

 var express = require( 'express' ), app = module.exports = express.createServer(), // ... more lines ... app.get( '/', routes.index.bind( app ) ); 

到目前为止,这是非常简单的。 目前唯一的例外是在我的app.configure调用中,我没有调用.use( express.static() ) 。 那是因为.routes.index()方法现在看起来如此:

 var fs = require( 'fs' ), // ... more lines ... exports.index = function( req, res ) { var host = /(\w+\.)?(.*)\.\w+/.exec( req.header( 'host' ) ), app = this; switch( host[ 2 ] ) { case 'foo': app.use( express.static( '/var/www/foo' ) ); fs.readFile( '/var/www/foo/index.html', 'utf8', fileReadFoo ); break; case 'bar': app.use( express.static( '/var/www/bar' ) ); fs.readFile( '/var/www/bar/index.html', 'utf8', fileReadBar ); break; case 'baz': // ... lines ... res.render( 'index', { title: 'Baz Title example' } ); break; default: res.send('Sorry, I do not know how to handle that domain.'); } function fileReadFoo( err, text ) { res.send( text ); } function fileReadBar( err, text ) { res.send( text ); } }; 

这里发生的是,我分析host条目的req.header并parsing域名。 基于此,我调用.static()方法,使Express可以提供正确的静态资源等,而且,我只是简单地读取和发送index.html文件的内容。 我试图用Jade来提供简单的HTML文件 ,但是Jade中include指令只接受相对path。

然而,这确实有效,但我很不确定这是否是一个好的做法。

任何build议/帮助欢迎。


更新

我想我需要把这个更清楚。 我不是一个初学者。 我很清楚ES如何工作,以及像NGINX这样的其他服务器。 我正在寻找有关NodeJS / Express正确的解决scheme。 如果使用Node / Express没有任何意义,请详细说明。 如果Node / Express有更好的方法,请解释一下。

谢谢 :-)

我喜欢使用bouncy作为前端反向代理 – 这可以让你运行完全不同的快速堆栈作为不同的服务器进程(每个具有不同的function和健壮性分开)…

然后您可以决定如何路由到不同的端口,它适用于WebSockets。

 var bouncy = require('bouncy'); bouncy(function (req, bounce) { if (req.headers.host === 'bouncy.example.com') { bounce(8000); } else if (req.headers.host === 'trampoline.example.com') { bounce(8001) } }).listen(80); 

瓦迪几乎是正确的想法 。 您可以configuration如何使用vhost中间件响应每个域:

 // `baz.com` var app = express.createServer(); app.get( '/', routes.index ); // ... express.createServer() .use( express.vhost( 'foo.com', express.static( '/var/www/foo' ) ) ) .use( express.vhost( 'bar.net', express.static( '/var/www/bar' ) ) ) .use( express.vhost( 'baz.com', app ) ) .use( function( req, res ) { res.send('Sorry, I do not know how to handle that domain.'); }) .listen( ... ); 

routes.index可以简化为只处理baz.com请求:

 exports.index = function( req, res ) { // ... lines ... res.render( 'index', { title: 'Baz Title example' } ); }; 

编辑

至于比较:

switch将首先完成,并确定如何处理基于host所有请求 – 类似于:

 express.createServer().use(function( req, res, next ) { switch( req.host ) { case 'foo.com': express.static( '/var/www/foo' )( req, res, next ); break; case 'bar.net': express.static( '/var/www/bar' )( req, res, next ); break; case 'baz.com': app.handle( req, res, next ); break; default: res.send( ... ); } }).listen( ... ); 

它允许您在启动时设置堆栈,以便任何中间件立即可用:

 server.stack = [ express.vhost( 'foo.com', ... ), express.vhost( 'bar.net', ... ), express.vhost( 'baz.com', ... ), [Function] ]; 

这些还反映了您可能遇到的两个可能的问题来源:

同样的堆栈没有filter

每个Application只有1个中间件堆栈,所有正在使用的中间件都被直接添加到app.use(...) 。 尽pipe增加了一些条件下,你仍然得到:

 app.stack = [ // ..., app.router, express.static( '/var/www/foo' ), express.static( '/var/www/bar' ) ]; 

条件不会改变static中间件如何响应 – 这是由req.path ,而不是req.host – 只有当他们在堆栈中开始响应。

堆栈的状态

而且,如果直到另一个请求完成之后才添加static中间件,那么我认为它们不是立即可用的:

 // GET http://foo.com/file 404 app.stack = [ app.router ] // GET http://foo.com/ 200 app.stack = [ app.router, express.static( '/var/www/foo' ) ] // GET http://foo.com/file 200 app.stack = [ app.router, express.static( '/var/www/foo' ) ] 

这也意味着可以将相同的static中间件多次添加到堆栈中:

 // 3x GET http://foo.com/ app.stack = [ app.router, express.static( '/var/www/foo' ), express.static( '/var/www/foo' ), express.static( '/var/www/foo' ) ] 

而且,如果有其他的要求,也会提出一个可能的竞争条件:

 // was `foo.com` or `bar.net` first? app.stack = [ app.router, express.static( ? ), express.static( ? ) ] 

我使用nginx作为node.js的前台服务器。 这是组织域,静态内容交付,负载控制和许多其他强大function的最佳解决scheme。 绝对不需要在节点事件循环中进行。 这将决定你的应用程序的速度。

在不知道约束条件的情况下回答这个问题是相当困难的,这意味着你必须在同一个进程中运行主机,所以我会回应其他人说的,但是希望给出更多的上下文。

使用节点的“最正确的”事情是在多个进程中运行主机,并在另一个进程中反向代理请求。 在同一个进程中运行多个站点会遇到各种问题,尤其是在一个站点崩溃的情况下,将所有站点都closures,需要重新启动整个进程。 Node的哲学非常像unix,它鼓励保持程序小而分离。 如果你分离的过程,你会得到一个自然的应用程序隔离。 如果你追求一个单一的devise,你将不得不编写和维护逻辑从不同的站点分离日志和error handling逻辑将变得更加复杂。 毫无疑问,您需要根据主机来分支逻辑,但是您的应用程序devise将会鼓励而不是阻止。

如果你不愿意使用其他技术栈(或者担心nginx目前缺乏对稳定分支中websockets的支持),那么在nodejs中有几个坚实的反向代理 ,包括nodejitsu的http代理在Joyent的云和弹性 (在另一个答案中提到)生产PaaS堆栈,但function较less,但我相信正在使用在浏览器上的生产。

弹性作者实际上甚至认为它是devisenodejs系统中最重要的架构模式之一 。 你也可能会注意到他的答案已经被一些核心节点提交者提升了。

由于Express使用Connect ,我相当确定您可以使用Connect的虚拟主机中间件。 它的操作与其他产品上的其他虚拟主机模块类似。 我没有多个域来testing和显示你正确的代码,但我会认为这是这样的:

 express.createServer() .use(express.vhost('hostname1.com', require('/path/to/hostname1').app) .use(express.vhost('hostname2.com', require('/path/to/hostname2').app) .listen(80) 

如果您已经达到了某个Express服务器不够的地步,那么请使用API​​中的Node.Cluster。 如果这还不够,那么目前的做法是在您的Express服务器前放置一个asnyc反向代理(如Nginx),并将代理指向您的Express服务器。

有点反对stream量,我不得不说,我不明白如何做这样的事情是有道理的。 Node.js有一个进程devise约束。 节streamIO对于一个Web应用程序来说是很难的,更不用说less数。 试图通过让多个应用程序将代码复杂化使其不可读取来抽象。 单个应用程序中的错误可能会影响所有应用程序。 这是一个非常不稳定的configuration。

如果你想看看你能不能做到,我想答案是肯定的。 在另一个答案中, 这里提到了一些像vhost的东西。 另一方面,我可能会与某种关注的分离和限制我的应用程序。 如果它被放置在同一个服务器框中,我将执行以下操作:

  1. 可用的核心数量为-1将是我将绑定到单个服务器的域的数量。
  2. 每个核心将持有一个node.js进程绑定到它。 它将实现一个单一网站的Web应用程序。
  3. 备用核心将拥有某种“路由器”,可以是一个nginx解决scheme,也可以是另一个用于路由数据的node.js / express应用程序。

总之,不要去想大,想想走。

缺点:这是一种不同的缩放方式。 只有这么多的果汁,你可以从一个盒子里出来。 当我们谈论“多箱”环境时,我不确定如何扩展这个想法。