使用 Express.js (node.js) 进行动态路由的最佳方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15344628/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 13:48:54  来源:igfitidea点击:

Best way to do dynamic routing with Express.js (node.js)

jsonnode.jscontent-management-systemexpressrouter

提问by Toni L?hdekorpi

I'm trying to create a simple CMS with express.js that dynamically creates routes. It gets a JSON from a database that looks like this:

我正在尝试使用动态创建路由的 express.js 创建一个简单的 CMS。它从如下所示的数据库中获取 JSON:

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'}
    }
}

and iterates over the objects creating routes like so:

并迭代创建路由的对象,如下所示:

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

Now everything is working fine. But the problem is, every time a user modifies the content and paths, the whole node app needs to be restarted. I didin't find any API calls to remove routes.

现在一切正常。但问题是,每次用户修改内容和路径时,整个节点应用程序都需要重新启动。我没有找到任何用于删除路由的 API 调用。

Is there any way to safely remove the old routes set with app.get? Should I even do that?

有什么办法可以安全地删除用 app.get 设置的旧路由吗?我应该这样做吗?

Is there a better way to do this kind of routing? I do like this method as it allows me to use the built in function, is fast and supports regex.

有没有更好的方法来做这种路由?我喜欢这种方法,因为它允许我使用内置函数,速度快并且支持正则表达式。

I tried removing the whole app.routes with app.routes = nul but it didn't do anything, the old routes were still in place.

我尝试使用 app.routes = nul 删除整个 app.routes 但它没有做任何事情,旧路由仍然存在。

One thing that did indeed remove them was

确实删除它们的一件事是

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

But does this actually remove them and is it safe to use so I don't end up hiHymaning huge amounts of ram if the router keeps getting repopulated?

但这是否真的删除了它们并且使用是否安全,所以如果路由器不断重新填充,我最终不会劫持大量内存?

回答by Max

As @supermova said in the comments, it is possible to update Express on-the-fly. Another architecture to consider is the one similar to classic CMSs (like Wordpress, for example). In other CMSs, all requests go to the same 'callback' and on every requestyou look up in the database what page to serve for that URL.

正如@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
       });
   });
});

There is a significant speed decrease as a result of this method, but in the end I think it is more sane. If speed is a huge issue you can set up a caching system (like Varnish) but there will be headaches with the approach of modifying Express routes on-the-fly. For example, what if you have to scale to two web servers? How do you keep them in sync if server A gets the 'create page' request and so it knows to update its routes, but what about server B? With every request going to the database you will be able to scale horizontally better.

这种方法的结果是速度显着下降,但最终我认为它更理智。如果速度是一个大问题,您可以设置一个缓存系统(如 Varnish),但是动态修改 Express 路由的方法会让人头疼。例如,如果您必须扩展到两个 Web 服务器怎么办?如果服务器 A 收到“创建页面”请求并且知道更新其路由,您如何使它们保持同步,但是服务器 B 呢?随着每个请求进入数据库,您将能够更好地横向扩展。

回答by Brandon

I would be very careful trying to create or destroy routes at runtime. Although you can change the data structures yourself, I do not believe these are documented as API's, so you risk this breaking if/when you upgrade Express.

我会非常小心地尝试在运行时创建或销毁路由。尽管您可以自己更改数据结构,但我不相信这些数据结构被记录为 API,因此如果/当您升级 Express 时,您可能会遇到这种破坏的风险。

This could also serve as a memory constraint if you create a new route for each database object because the set of pages can grow to who knows how big.

如果您为每个数据库对象创建一个新路由,这也可以用作内存约束,因为页面集可能会增长到谁知道有多大。

Look at it like this... you don't want new routes; you want to add URL's to existing routes. If you are adding a route, that means you want some URL to map to some distinct function. But you are mapping each URL to the same function. In essence, you are only adding routes by side effect. What you care about is that some dynamic set of URL's map to a specific function.

这样看……你不想要新的路线;您想将 URL 添加到现有路由。如果您要添加路由,则意味着您希望某个 URL 映射到某个不同的功能。但是您将每个 URL 映射到相同的函数。本质上,您只是通过副作用添加路由。你关心的是一些动态的 URL 集映射到一个特定的函数。

Can you instead use a wildcard to map the URL pattern to a specific function, like

您可以改为使用通配符将 URL 模式映射到特定函数,例如

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

And manage the pagesfromdb mapping outside of the express layer. You can use direct database access, cache + database access or a timer-based refresher, whatever performs best for you.

并在 express 层之外管理 pagesfromdb 映射。您可以使用直接数据库访问、缓存 + 数据库访问或基于计时器的复习,任何对您最有利的方法。

回答by Albin

Adding routes can be done on the fly, as mentioned. Deleting can too, given this fuction:

如前所述,可以即时添加路由。鉴于此功能,删除也可以:

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

(stolen from Removing a specfic mapped route in Node.js at runtime removes static mapping?)

在运行时删除 Node.js 中的特定映射路由会删除静态映射?

Updating routes like this does make your app "stateful", and will probably lead to a problems if you need load balance.

像这样更新路由确实会使您的应用程序“有状态”,如果您需要负载平衡,可能会导致问题。