javascript ExpressJS 服务器 - 如何处理多个域
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11960705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ExpressJS Server - How to handle multiple domains
提问by jAndy
I'm fooling around a little with Express and I'm wondering, what the "most correct" way is to handle multiple domains which are linked to the same server.
我在 Express 上玩弄了一点,我想知道“最正确”的方法是处理链接到同一服务器的多个域。
Lets assume we have
让我们假设我们有
- foo.com
- bar.net
- baz.com
- 富网
- 网吧
- 巴兹网
which all point to 111.222.333.444
. That machine is running NodeJS with Express. My current solution looks like this:
这都指向111.222.333.444
. 那台机器正在使用 Express 运行 NodeJS。我目前的解决方案是这样的:
var express = require( 'express' ),
app = module.exports = express.createServer(),
// ... more lines ...
app.get( '/', routes.index.bind( app ) );
Thus far this is pretty straightforward. The only exception so far is in my app.configure
call, where I didn't make a call to .use( express.static() )
. Thats because the .routes.index()
method looks like so right now:
到目前为止,这是非常简单的。到目前为止唯一的例外是在我的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 );
}
};
What happens here is, that I analyse the req.header
for the host
entry and parse the domain name. Based on that, I call the .static()
method so Expresscan serve the right static resources etc., furthermore, I just simply read and send the contents of the index.htmlfiles. I tried to use Jadeaswell for serving plain HTML files, but the include
directive in Jadeonly accepts relative pathes.
这里发生的是,我分析req.header
了host
进入和解析的域名。基于此,我调用该.static()
方法,以便Express可以提供正确的静态资源等,此外,我只是简单地读取和发送index.html文件的内容。我也尝试使用Jade来提供纯HTML 文件,但Jade 中的include
指令只接受相对路径。
However, this indeed works, but I'm pretty unsure if that is a good practice.
然而,这确实有效,但我不确定这是否是一个好的做法。
Any advice / help welcome.
欢迎任何建议/帮助。
Update
更新
I think I need to make this more clear. I'm not a beginner by any means. I'm very aware how ES works and other servers like NGINX. I'm looking for qualified answers on what the right thing with NodeJS/Express is. If it doesn't make any sense to use Node/Express for that, please elaborate. If there is a better way to do this with Node/Express, please explain.
我想我需要更清楚地说明这一点。无论如何,我不是初学者。我非常了解 ES 和 NGINX 等其他服务器的工作原理。我正在寻找有关 NodeJS/Express 正确之处的合格答案。如果为此使用 Node/Express 没有任何意义,请详细说明。如果使用 Node/Express 有更好的方法可以做到这一点,请解释。
Thanks :-)
谢谢 :-)
采纳答案by Bino Carlos
I like to use bouncyas a front end reverse-proxy - this lets you run totally different express stacks as different server processes (each with different features and separated for robustness)...
我喜欢使用bouncy作为前端反向代理 - 这使您可以将完全不同的快速堆栈作为不同的服务器进程运行(每个进程具有不同的功能,并且为了健壮性而分开)...
You can then decide how to route to different ports, it works fine with WebSockets.
然后您可以决定如何路由到不同的端口,它可以很好地与 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);
回答by Jonathan Lonowski
Vadim was almost onto the right idea. You can configure how to respond to each domain with the vhost
middleware:
Vadim的想法几乎是正确的。您可以配置如何使用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
can then be simplified to handle only baz.com
requests:
routes.index
然后可以简化为仅处理baz.com
请求:
exports.index = function( req, res ) {
// ... lines ...
res.render( 'index', { title: 'Baz Title example' } );
};
Edit
编辑
As for comparisons:
至于比较:
The switch
would effectively be done first and would determine how to handle all requests based on the host
-- similar to:
将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( ... );
It allows you to set the stack on start so any middleware is available immediately:
它允许您在启动时设置堆栈,以便任何中间件立即可用:
server.stack = [
express.vhost( 'foo.com', ... ),
express.vhost( 'bar.net', ... ),
express.vhost( 'baz.com', ... ),
[Function]
];
These also reflect the 2 possible sources of issues you might have:
这些也反映了您可能遇到的 2 个可能的问题来源:
Same stack without filters
没有过滤器的相同堆栈
Each Application
only has 1 middleware stack, which all of the middleware you're using is being added directly to with app.use(...)
. Despite adding some under conditions, you're still getting:
每个Application
只有 1 个中间件堆栈,您使用的所有中间件都直接添加到 with app.use(...)
. 尽管在条件下添加了一些,您仍然会得到:
app.stack = [
// ...,
app.router,
express.static( '/var/www/foo' ),
express.static( '/var/www/bar' )
];
And the condition won't change how the static
middlewares respond -- which is by req.path
, not req.host
-- only when they're in the stack to start responding.
并且条件不会改变static
中间件的响应方式——这是通过req.path
,不是req.host
——只有当它们在堆栈中开始响应时。
State of the stack
堆栈状态
And, if the static
middlewares aren't added until afteranother request has been made, then I take it they aren't available immediately:
而且,如果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' ) ]
This may also mean the same static
middleware could be added to the stack multiple times:
这也可能意味着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' )
]
And having their addition depend on other requests also suggests a possible race conditions:
并且根据其他请求添加它们也表明可能存在竞争条件:
// was `foo.com` or `bar.net` first?
app.stack = [
app.router,
express.static( ? ),
express.static( ? )
]
回答by Vadim Baryshev
I use nginxas front-server with node.js. It's the best solution to organize domains, static content delivery, load control and many other powerful features. Absolutely no need to do it in node event loop. This will determine the speed of your application.
我使用nginx作为 node.js 的前端服务器。它是组织域、静态内容交付、负载控制和许多其他强大功能的最佳解决方案。绝对不需要在节点事件循环中进行。这将决定您的应用程序的速度。
回答by Raoul
It's quite difficult to answer this without knowing the constraints that meant you mustrun the hosts in the same process, so I'll echo what others have said, but hopefully give some more context.
如果不知道意味着您必须在同一进程中运行主机的约束,就很难回答这个问题,所以我会回应其他人所说的话,但希望提供更多背景信息。
The "most correct" thing to do with node is to run the hosts in multiple processes and to reverse proxy the requests in another process. Running multiple sites in the same process is riddled with problems, not least of which is a crash in one, brings them all down and requires a restart of the whole process. Node's philosophy is very unix-like, it encourages keeping programs small and separate. If you separate the processes, you'll get a natural segregation of applications. If you pursue a monolithic design, you'll have to write and maintain logic to separate logging from the different sites and error handling logic will become more complicated. There are no doubt other cases where you'll need to branch logic based on host, but your application design will encourage rather than discourage that.
对 node 做的“最正确”的事情是在多个进程中运行主机,并在另一个进程中反向代理请求。在同一进程中运行多个站点会出现问题,其中最重要的是一个崩溃,将它们全部关闭并需要重新启动整个进程。Node 的哲学非常类似于 unix,它鼓励保持程序小而独立。如果您将进程分开,您将获得应用程序的自然分离。如果您追求单体式设计,则必须编写和维护逻辑以将日志记录与不同站点分开,并且错误处理逻辑将变得更加复杂。毫无疑问,在其他情况下您需要根据主机对逻辑进行分支,但您的应用程序设计将鼓励而不是阻止这种情况。
If you're averse to other technology stacks (or are concerned e.g. by nginx's current lack of support of websockets in the stable branch), then there are a few solid reverse proxys written in nodejs, including nodejitsu's http-proxywhich is used in their production PaaS stack on Joyent's cloud and bouncy(mentioned in another answer) which has less features, but I believe is being used in production on browserling.
如果你不喜欢其他技术栈(或者担心 nginx 目前在稳定分支中缺乏对 websockets 的支持),那么有一些用 nodejs 编写的可靠的反向代理,包括 nodejitsu 的http-proxy,它在他们的Joyent 的云和bouncy上的生产 PaaS 堆栈(在另一个答案中提到)功能较少,但我相信正在浏览器的生产中使用。
The author of bouncy actually goes as far as suggesting it as one of the most important architectural patterns in designing a nodejs system. You may also notice that his answer has been upvoted by some of the core node committers.
bouncy 的作者实际上甚至暗示它是设计 nodejs 系统时最重要的架构模式之一。您可能还注意到,他的回答已经得到了一些核心节点提交者的支持。
回答by Sunny
I would not recommend using Express in the first place. In fact, even for a single domain, using Node's http module, one can easily write an app with all the functionality that you get with Express.
我不建议首先使用 Express。事实上,即使对于单个域,使用 Node 的 http 模块,也可以轻松编写具有 Express 所具有的所有功能的应用程序。
For multiple domains, once you get the hostname, you can customize your routes or middleware or whatever you want to call them. As long as you do not have any blocking calls in any of the app, the number of domains your singe node process is going to serve is irrelevant. If CPU usage becomes a bottleneck, you can use cluster of the same process.
对于多个域,一旦获得主机名,您就可以自定义您的路由或中间件或任何您想调用的名称。只要您在任何应用程序中都没有任何阻塞调用,您的单节点进程将服务的域数量是无关紧要的。如果 CPU 使用成为瓶颈,您可以使用相同进程的集群。
Clustering is not possible if you have in-memory session data. You will need another process to maintain state of which instance is managing that particular session. ALl this depends on how you are managing states, persistence of states, etc.
如果您有内存中的会话数据,则无法进行聚类。您将需要另一个进程来维护哪个实例正在管理该特定会话的状态。所有这一切都取决于您如何管理状态、状态的持久性等。
Overall, the answer is not simple unless other details are provided. I am providing a separate answer, rather than a comment because I BELIEVE THAT TOO MANY DEVELOPERS USE EXPRESS AND THEREBY LIMIT THEIR FLEXIBILITY.
总的来说,除非提供其他细节,否则答案并不简单。我提供一个单独的答案,而不是评论,因为我相信太多的开发者使用快递并因此限制了他们的灵活性。
回答by qballer
Going somewhat against the flow I would have to say that I don't see how doing something like that makes sense. Node.js has a one process design constrain. Throttling IO is hard work for one web application let alone a few. Trying to abstract that by having several applications will over complicate the code making it unreadable. A bug in a single application can impact all applications. This is a very unstable configuration.
有点逆流而上,我不得不说我不明白做这样的事情有什么意义。Node.js 有一个单一的流程设计约束。对于一个 Web 应用程序来说,限制 IO 是一项艰巨的工作,更不用说几个了。试图通过拥有多个应用程序来抽象它会使代码变得过于复杂,使其变得不可读。单个应用程序中的错误可能会影响所有应用程序。这是一个非常不稳定的配置。
If you're looking to see if you can do it, I guess the answer is yes. Something like vhost suggested herein another answer. On the other hand, I would probably go with some kind of separation of concerns and constrain my app. If it's to be placed in the same server box I would do the following:
如果你想看看你是否能做到,我想答案是肯定的。像虚拟主机建议的东西在这里的另一种回答。另一方面,我可能会采用某种关注点分离并限制我的应用程序。如果要将其放置在同一个服务器盒中,我会执行以下操作:
- The number of available cores -1 will be the number of domains I would bind to a single server.
- Each core will hold a node.js process bounded to it. It will implement a single web application covering a single website.
- the spare core will hold some kind of a "router", either an nginx solution or another node.js/express application which routes the data.
- 可用核心数 -1 将是我将绑定到单个服务器的域数。
- 每个核心都将持有一个绑定到它的 node.js 进程。它将实现覆盖单个网站的单个 Web 应用程序。
- 备用核心将包含某种“路由器”,可以是 nginx 解决方案,也可以是另一个路由数据的 node.js/express 应用程序。
In short, don't think about going big, think about going wide.
总之,不要想着做大,想着做大。
Drawback: It's a different way of scaling. There is only so much of juice you can get out of a single box. I'm not sure how to scale this idea when we are talking about a "multi-box" environment.
缺点:这是一种不同的缩放方式。您可以从一个盒子中取出这么多果汁。当我们谈论“多盒”环境时,我不确定如何扩展这个想法。
回答by EhevuTov
Since Express uses Connect, I'm pretty sure you can use Connect's virtual host middleware. It operates similar to other vhost modules on other products. I don't have multiple domains to test and show you proper code, but I would think it's something like this:
由于 Express 使用Connect,我很确定您可以使用 Connect 的虚拟主机中间件。它的操作类似于其他产品上的其他 vhost 模块。我没有多个域来测试并向您展示正确的代码,但我认为它是这样的:
express.createServer()
.use(express.vhost('hostname1.com', require('/path/to/hostname1').app)
.use(express.vhost('hostname2.com', require('/path/to/hostname2').app)
.listen(80)
If you get to the point where one Express server isn't enough, then look into using the Node.Cluster from the API. If that also isn't enough, then the current practice is to put a asnyc reverse proxy such as Nginx in front of your Express servers and point the proxies to your Express servers.
如果您发现一台 Express 服务器不够用,请考虑使用 API 中的 Node.Cluster。如果这还不够,那么当前的做法是在您的 Express 服务器前面放置一个 asnyc 反向代理,例如 Nginx,并将代理指向您的 Express 服务器。