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将是我将绑定到单个服务器的域的数量。
- 每个核心将持有一个node.js进程绑定到它。 它将实现一个单一网站的Web应用程序。
- 备用核心将拥有某种“路由器”,可以是一个nginx解决scheme,也可以是另一个用于路由数据的node.js / express应用程序。
总之,不要去想大,想想走。
缺点:这是一种不同的缩放方式。 只有这么多的果汁,你可以从一个盒子里出来。 当我们谈论“多箱”环境时,我不确定如何扩展这个想法。