Подтвердить что ты не робот

ExpressJS Server - как обрабатывать несколько доменов

Я немного обманываюсь с помощью Express, и мне интересно, какой "самый правильный" способ - обрабатывать несколько доменов, которые связаны с одним и тем же сервером.

Предположим, что

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

которые все указывают на 111.222.333.444. Эта машина работает с NodeJS с Express. Мое текущее решение выглядит так:

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.header для записи host и разбираю имя домена. Исходя из этого, я вызываю метод .static(), поэтому Express может обслуживать правильные статические ресурсы и т.д., Кроме того, я просто просто читаю и отправляю содержимое файлов index.html. Я попытался использовать Jade для обслуживания обычных HTML файлов, но директива include в Jade принимает только относительные пути.

Однако это действительно работает, но я не уверен, что это хорошая практика.

Любые советы/помощь приветствуются.


Обновление

Думаю, мне нужно сделать это более ясным. Я не новичок. Я очень хорошо знаю, как работает ES, и других серверов, таких как NGINX. Я ищу квалифицированные ответы на то, что правильно с NodeJS/Express. Если это не имеет смысла использовать Node/Express для этого, пожалуйста, уточните. Если есть лучший способ сделать это с помощью Node/Express, пожалуйста, объясните.

Спасибо: -)

4b9b3361

Ответ 1

Мне нравится использовать bouncy в качестве обратного прокси-сервера на переднем конце - это позволяет запускать совершенно разные экспресс-пакеты как разные серверные процессы ( каждый с различными функциями и разделенными на надежность)...

Затем вы можете решить, как перенаправить на разные порты, он отлично работает с 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);

Ответ 2

Вадим был почти на правильной идее. Вы можете настроить способ ответа на каждый домен с помощью vhost middleware:

// `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' } );
};

Edit

Что касается сравнений:

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 middlewares - который находится на req.path, а не req.host - только когда они находятся в стеке, чтобы начать отвечать.

Состояние стека

И, если static middlewares не добавляются до тех пор, пока не будет выполнен другой запрос, я полагаю, что они недоступны сразу:

// 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( ? )
]

Ответ 3

Я использую nginx как front-server с node.js. Это лучшее решение для организации доменов, доставки статического контента, управления нагрузкой и многих других мощных функций. Абсолютно не нужно делать это в цикле событий node. Это определит скорость вашего приложения.

Ответ 4

Трудно ответить на это, не зная ограничений, которые означали, что вы должны запускать хосты в одном процессе, поэтому я буду повторять то, что сказали другие, но, надеюсь, дадим еще какой-то контекст.

"Самая правильная" вещь, связанная с node, заключается в том, чтобы запускать узлы в нескольких процессах и перенаправлять прокси-запросы в другой процесс. Запуск нескольких сайтов в одном и том же процессе пронизан проблемами, не последним из которых является крах в одном, сводит их все и требует перезагрузки всего процесса. node философия очень похожа на UNIX, она поощряет сохранение небольших и отдельных программ. Если вы отделите процессы, вы получите естественную сегрегацию приложений. Если вы преследуете монолитный дизайн, вам придется писать и поддерживать логику для разделения ведения журнала с разных сайтов, и логика обработки ошибок будет усложняться. Нет никаких сомнений в других случаях, когда вам понадобится разветкить логику на основе хоста, но ваш дизайн приложения будет поощрять, а не препятствовать этому.

Если вы не согласны с другими технологическими стеками (или, к примеру, из-за отсутствия nginx поддержки websockets в устойчивой ветки), тогда есть несколько твердых обратных прокси, написанных в nodejs, включая nodejitsu http-proxy, который используется в их производственном стеке PaaS для облака Joyent и bouncy (упоминается в другом ответе), который имеет меньше возможностей, но я считаю, что он используется в процессе обработки браузера.

Автор bouncy фактически доходит до того, что предлагает один из самых важных архитектурных шаблонов при проектировании системы nodejs. Вы также можете заметить, что его ответ был поддержан некоторыми из основных коммандеров node.

Ответ 5

Идя несколько против потока, я должен был сказать, что я не вижу, как это делает что-то подобное. Node.js имеет один ограничитель проектирования процесса. Throttling IO - тяжелая работа для одного веб-приложения, не говоря уже о нескольких. Попытка абстрагироваться от того, что несколько приложений будут усложнять код, делая его нечитаемым. Ошибка в одном приложении может повлиять на все приложения. Это очень неустойчивая конфигурация.

Если вы хотите посмотреть, сможете ли вы это сделать, я думаю, что да. Что-то вроде vhost предложил здесь в другом ответе. С другой стороны, я бы, вероятно, пошел с каким-то разделением проблем и ограничил мое приложение. Если он будет помещен в один и тот же серверный ящик, я бы сделал следующее:

  • Количество доступных ядер -1 будет количеством доменов, которые я бы привязал к одному серверу.
  • Каждое ядро ​​проведет ограниченный с ним процесс Node.js. Он будет внедрять одно веб-приложение, охватывающее один веб-сайт.
  • резервное ядро ​​будет содержать какой-то "маршрутизатор", либо решение nginx, либо другое приложение Node.js/express, которое направляет данные.

Короче говоря, не думайте о том, чтобы стать большим, подумайте о том, чтобы пройти.

Минус: Это другой способ масштабирования. Существует только столько сока, что вы можете выбраться из одной коробки. Я не уверен, как масштабировать эту идею, когда мы говорим о среде с несколькими ящиками.

Ответ 6

Так как Express использует Connect, я уверен, что вы можете использовать промежуточное ПО Connect virtual host. Он работает аналогично другим модулям 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)

Если вы дойдете до того, что одного Express-сервера недостаточно, изучите использование Node.Cluster из API. Если этого также недостаточно, то текущая практика заключается в том, чтобы поставить обратный прокси asnyc, такой как Nginx, перед вашими экспресс-серверами и указать прокси на ваши серверы Express.