2013-03-11 2 views
13

Я пытаюсь создать простую CMS с express.js, которая динамически создает маршруты. Он получает JSON из базы данных, которая выглядит следующим образом:Лучший способ динамической маршрутизации с помощью Express.js (node.js)

pagesfromdb = { 
    home = { 
     paths = ['/','/home','/koti'], 
     render = 'home.ejs', 
     fi_FI = {html='<h1>Hei maailma!</h1>'}, 
     en_US = {html='<h1>Hello World!</h1>'} 
    }, 
    about = { 
     paths = ['/about','/tietoja'], 
     render = 'general.ejs', 
     fi_FI = {html='Tietoja'}, 
     en_US = {html='About Us'} 
    } 
} 

и итерацию над объектами, создавая маршруты, как так:

Object.keys(pagesfromdb).forEach(function(key) { 
    var page = pagesfromdb[key]; 
    app.get(page.global.paths,function(req, res){ 
     res.render(page.render, page[language]); 
    }); 
}); 

Теперь все работает нормально. Но проблема в том, что каждый раз, когда пользователь изменяет содержимое и пути, все приложение узла нужно перезапустить. Я не нашел никаких вызовов API для удаления маршрутов.

Есть ли способ безопасно удалить старые маршруты с помощью app.get? Должен ли я это сделать?

Есть ли лучший способ сделать такую ​​маршрутизацию? Мне нравится этот метод, поскольку он позволяет мне использовать встроенную функцию, быстро и поддерживает регулярное выражение.

Я попытался удалить все app.routes с помощью app.routes = nul, но ничего не сделал, старые маршруты все еще были на месте.

Одна вещи, которая действительно удалить их была

delete app._router.map.get; 
app._router.map.get = []; 

Но это на самом деле удалить их и безопасно использовать, так что я не до конца угона огромного количества оперативной памяти, если маршрутизатор продолжает получать заселен?

+2

AFAIk express сохраняет все маршруты в app._router.map , поэтому это должно работать. – supernova

+0

Есть ли какие-либо кеши, связанные с рендером, о котором я должен беспокоиться. Или они просто удалены с app._router.map, так как они находятся под ним? –

+1

в режиме производства выражает представления кэшей, кэш можно получить через app.cache [viewname]. – supernova

ответ

12

Как пояснила @supermova в комментариях, можно обновить Express на лету. Другая архитектура, которую следует учитывать, - та, которая похожа на классические CMS (например, Wordpress). В других CMS все запросы переходят в один и тот же «обратный вызов», а по каждый запрос вы просматриваете в базе данных, какую страницу будет отображаться для этого URL-адреса.

app.get('/*', function (req, res) { 
    db.findPage({ slug: req.url}, function (err, pageData) { 
     res.render('page-template', { 
      pageContent: pageData.content, 
      pageTitle: pageData.title 
     }); 
    }); 
}); 

В результате этого метода происходит значительное снижение скорости, но, в конце концов, я думаю, что это более разумно. Если скорость - это огромная проблема, вы можете настроить систему кеширования (например, Varnish), но будут проблемы с изменением маршрутов Express на лету. Например, что делать, если вам нужно масштабировать до двух веб-серверов? Как вы храните их в синхронизации, если сервер A получает запрос «создать страницу», и поэтому он знает, как обновлять маршруты, но как насчет сервера B? С каждым запросом, отправляющимся в базу данных, вы сможете масштабировать горизонтально лучше.

+0

Я уже использую Varnish, но IMO это неправильный подход, чтобы исправить ситуацию ... Это на самом деле ужасно медленно, когда есть много страниц по сравнению с динамическим созданием маршрутов. –

1

Я был бы очень осторожен, пытаясь создать или уничтожить маршруты во время выполнения. Хотя вы сами можете изменить структуры данных, я не считаю, что они документированы как API, поэтому вы рискуете этим сломаться, если/при обновлении Express.

Это может также служить ограничением памяти, если вы создаете новый маршрут для каждого объекта базы данных, потому что набор страниц может вырасти до того, кто знает, насколько большой.

Посмотрите на это вот так: вам не нужны новые маршруты; вы хотите добавить URL к существующим маршрутам. Если вы добавляете маршрут, это означает, что вы хотите, чтобы какой-то URL-адрес отображался в какой-то отдельной функции. Но вы сопоставляете каждый URL-адрес с той же функцией. По сути, вы добавляете маршруты только побочным эффектом. Что вам нужно, так это то, что некоторый динамический набор URL-адресов привязан к определенной функции.

Вы можете использовать вместо этого символа, чтобы отобразить шаблон URL для конкретной функции, как

app.get('/pages/*', function(req, res) { 
    var page = pagesfromdb[key]; 
    if (page != null) { 
     res.render(page.render, page.language) 
    } 
    else { 
     res.send(404); 
    } 
}); 

И управлять отображением pagesfromdb вне специального слоя. Вы можете использовать прямой доступ к базе данных, доступ к кеш-памяти или доступ к базам данных или обновить таймер, что лучше всего подходит для вас.

+0

Проблема с этим методом заключается в том, что мне нужно воссоздать функциональность regexp. –

+0

В качестве продолжения моего первого вопроса. Есть ли способ перезапустить приложение узла внутри себя, не прибегая к каким-либо оберткам? –

+0

Это можно сделать, да, но не легко. Вы можете начать самостоятельно, используя process.execPath и process.argv [1]. Но для того, чтобы это сработало, вы должны сначала отключить любые сетевые сокеты и разблокировать любые файлы ... очистка общего ресурса. – Brandon

0

Добавление маршрутов может выполняться «на лету», как уже упоминалось. Удаление может также, учитывая эту фикцию:

function deleteRoute(url) { 
    for (var i = app.routes.get.length - 1; i >= 0; i--) { 
    if (app.routes.get[i].path === "/" + url) { 
     app.routes.get.splice(i, 1); 
    } 
    } 
} 

(украдено из Removing a specfic mapped route in Node.js at runtime removes static mapping?)

Обновление маршрутов, как это сделать ваше приложение «с сохранением состояния», и, вероятно, приведет к проблемам, если вам нужен баланс нагрузки.

Смежные вопросы