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

你离开我真会死。 提交于 2019-11-30 01:21:30

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 request you look up in the database what page to serve for that 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.

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.

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.

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

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.

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?)

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!