31

私はExpressを少しいじっていますが、同じサーバーにリンクされている複数のドメインを処理するための「最も正しい」方法は何でしょうか。

私たちが持っていると仮定しましょう

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

これはすべてを指し111.222.333.444ます。そのマシンはExpressでNodeJSを実行しています。私の現在の解決策は次のようになります。

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 );
    }
};

ここで何が起こるかというとreq.headerhostエントリのを分析し、ドメイン名を解析します。これに基づいて、Express.static()が適切な静的リソースなどを提供できるようにメソッドを呼び出します。さらに、 index.htmlファイルの内容を読み取って送信するだけです。プレーンHTMLファイルを提供するためにもJadeを使用しようとしましたが、Jadeのディレクティブは相対パスのみを受け入れます。include

ただし、これは確かに機能しますが、それが良い習慣であるかどうかはかなりわかりません。

任意のアドバイス/ヘルプを歓迎します。


アップデート

これをもっと明確にする必要があると思います。私は決して初心者ではありません。ESがどのように機能するかやNGINXのような他のサーバーをよく知っています。NodeJS/Expressの正しい点についての適切な回答を探しています。そのためにNode/Expressを使用しても意味がない場合は、詳しく説明してください。Node / Expressでこれを行うためのより良い方法がある場合は、説明してください。

ありがとう :-)

4

7 に答える 7

39

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.indexbaz.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]
];

これらは、発生する可能性のある2つの問題の原因も反映しています。

フィルタなしの同じスタック

それぞれApplicationにミドルウェアスタックが1つしかないため、使用しているすべてのミドルウェアがに直接追加されapp.use(...)ます。条件の下でいくつかを追加したにもかかわらず、あなたはまだ得ています:

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( ? )
]
于 2012-08-14T22:43:59.657 に答える
18

私はバウンシーをフロントエンドのリバースプロキシとして使用するのが好きです-これにより、まったく異なるエクスプレススタックを異なるサーバープロセスとして実行できます(それぞれが異なる機能を持ち、堅牢性のために分離されています)...

次に、さまざまなポートにルーティングする方法を決定できます。これはWebSocketで正常に機能します。

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);
于 2012-08-14T22:55:57.650 に答える
4

同じプロセスでホストを実行する必要があるという制約を知らずにこれに答えるのは非常に難しいので、他の人が言ったことをエコーし​​ますが、うまくいけば、もう少しコンテキストを与えます。

ノードで行う「最も正しい」ことは、複数のプロセスでホストを実行し、別のプロセスで要求をリバースプロキシすることです。同じプロセスで複数のサイトを実行すると、問題が発生します。特に、1つのサイトがクラッシュすると、すべてがダウンし、プロセス全体を再起動する必要があります。Nodeの哲学は非常にUnixライクであり、プログラムを小さく分離しておくことを奨励しています。プロセスを分離すると、アプリケーションが自然に分離されます。モノリシック設計を追求する場合は、ログをさまざまなサイトから分離するためのロジックを記述して維持する必要があり、エラー処理ロジックはより複雑になります。ホストに基づいてロジックを分岐する必要がある他のケースは間違いありませんが、アプリケーションの設計では、それを思いとどまらせるのではなく、奨励します。

他のテクノロジースタックを嫌う場合(または、nginxが現在安定したブランチでWebSocketをサポートしていないことを懸念している場合)、nodejsで記述されたいくつかの堅実なリバースプロキシがあります。 Joyentのクラウド上の本番PaaSスタックと、機能が少ない弾力性(別の回答で言及)ですが、ブラウザーでの本番環境で使用されていると思います。

弾力性の作者は、実際には、nodejsシステムを設計する上で最も重要なアーキテクチャパターンの1つとしてそれを示唆しているところまで行きます。また、彼の回答がコアノードコミッターの一部によって支持されていることに気付くかもしれません。

于 2012-08-18T19:42:00.630 に答える
3

node.jsのフロントサーバーとしてnginxを使用しています。これは、ドメイン、静的コンテンツ配信、負荷制御、およびその他の多くの強力な機能を整理するための最良のソリューションです。ノードイベントループでそれを行う必要はまったくありません。これにより、アプリケーションの速度が決まります。

于 2012-08-14T21:23:37.683 に答える
3

ExpressはConnectを使用しているので、Connectの仮想ホストミドルウェアを使用できると確信しています。他の製品の他の仮想ホストモジュールと同様に動作します。適切なコードをテストして表示するための複数のドメインはありませんが、次のようなものだと思います。

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

1台のExpressサーバーでは不十分な場合は、APIからNode.Clusterを使用することを検討してください。それでも不十分な場合は、現在の方法では、NginxなどのasnycリバースプロキシをExpressサーバーの前に配置し、プロキシをExpressサーバーにポイントします。

于 2012-08-18T19:05:22.197 に答える
3

そもそもExpressの使用はお勧めしません。実際、単一のドメインの場合でも、Nodeのhttpモジュールを使用すると、Expressで得られるすべての機能を備えたアプリを簡単に作成できます。

複数のドメインの場合、ホスト名を取得したら、ルートやミドルウェア、またはそれらを呼び出したいものをカスタマイズできます。どのアプリにもブロッキング呼び出しがない限り、単一ノードプロセスが提供するドメインの数は関係ありません。CPU使用率がボトルネックになった場合は、同じプロセスのクラスターを使用できます。

メモリ内のセッションデータがある場合、クラスタリングはできません。どのインスタンスがその特定のセッションを管理しているかの状態を維持するために、別のプロセスが必要になります。これは、状態の管理方法、状態の永続性などによって異なります。

全体として、他の詳細が提供されない限り、答えは単純ではありません。コメントではなく、別の回答を提供します。これは、あまりにも多くの開発者がエクスプレスを使用しているため、柔軟性が制限されていると考えているためです。

于 2018-08-18T20:38:13.223 に答える
2

流れに逆らうと、そのようなことをするのがどうして意味があるのか​​わからないと言わざるを得ません。Node.jsには1つのプロセス設計の制約があります。IOの調整は、いくつかは言うまでもなく、1つのWebアプリケーションにとって大変な作業です。複数のアプリケーションを使用することでそれを抽象化しようとすると、コードが複雑になりすぎて判読できなくなります。単一のアプリケーションのバグは、すべてのアプリケーションに影響を与える可能性があります。これは非常に不安定な構成です。

あなたがそれを行うことができるかどうかを見たいのなら、答えはイエスだと思います。ここで別の答えで提案されたvhostのようなもの。一方で、私はおそらく何らかの関心の分離を行い、アプリを制約するでしょう。同じサーバーボックスに配置する場合は、次のようにします。

  1. 使用可能なコアの数-1は、単一のサーバーにバインドするドメインの数になります。
  2. 各コアは、それにバインドされたnode.jsプロセスを保持します。単一のWebサイトをカバーする単一のWebアプリケーションを実装します。
  3. スペアコアは、nginxソリューションまたはデータをルーティングする別のnode.js/expressアプリケーションのいずれかのある種の「ルーター」を保持します。

要するに、大きくなることを考えないで、広くなることを考えてください。

欠点:これはスケーリングの別の方法です。1つの箱から取り出せるジュースはたくさんあります。「マルチボックス」環境について話しているときに、このアイデアをどのようにスケーリングするかはわかりません。

于 2012-08-18T00:10:59.757 に答える