web-dev-qa-db-fra.com

Meilleure façon de faire du routage dynamique avec Express.js (node.js)

J'essaie de créer un simple CMS avec express.js qui crée de manière dynamique des itinéraires. Il obtient un JSON d'une base de données qui ressemble à ceci:

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

et itère sur les objets créant des itinéraires comme ceci:

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

Maintenant tout fonctionne bien. Mais le problème est que, chaque fois qu'un utilisateur modifie le contenu et les chemins, l'ensemble de l'application de nœud doit être redémarré. Je n'ai trouvé aucun appel d'API pour supprimer des itinéraires.

Existe-t-il un moyen de supprimer en toute sécurité les anciens itinéraires définis avec app.get? Devrais-je même faire ça?

Y a-t-il une meilleure façon de faire ce genre de routage? J'aime cette méthode, car elle me permet d'utiliser la fonction intégrée, est rapide et prend en charge les expressions régulières.

J'ai essayé de supprimer toutes les entrées.routes avec app.routes = nul mais cela ne faisait rien, les anciennes routes étaient toujours en place.

Une chose qui les a effectivement supprimés était

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

Mais est-ce que cela les supprime réellement et est-il sûr de les utiliser afin que je ne finisse pas par détourner d’énormes quantités de bélier si le routeur ne cesse de se repeupler?

14
Toni Lähdekorpi

Comme @supermova l'a déclaré dans les commentaires, il est possible de mettre à jour Express à la volée. Une autre architecture à considérer est celle similaire aux CMS classiques (comme Wordpress, par exemple). Dans d'autres systèmes de gestion de contenu, toutes les demandes sont dirigées vers le même 'callback' et sur à chaque demande vous recherchez dans la base de données quelle page servir pour cette URL.

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

Cette méthode entraîne une diminution importante de la vitesse, mais au final, je pense qu’elle est plus saine d’esprit. Si la vitesse est un problème énorme, vous pouvez configurer un système de mise en cache (comme Varnish), mais l'approche de la modification des itinéraires Express à la volée vous posera des problèmes. Par exemple, que se passe-t-il si vous devez évoluer vers deux serveurs Web? Comment les garder synchronisés si le serveur A reçoit la requête 'créer une page' et sait donc mettre à jour ses itinéraires, mais qu'en est-il du serveur B? Avec chaque demande allant à la base de données, vous pourrez mieux évoluer horizontalement.

14
Max

Je ferais très attention d'essayer de créer ou de détruire des itinéraires au moment de l'exécution. Bien que vous puissiez modifier vous-même les structures de données, je ne pense pas qu'elles soient documentées en tant qu'API. Vous risquez donc cette interruption si/lorsque vous mettez à niveau Express.

Cela pourrait également servir de contrainte de mémoire si vous créez une nouvelle route pour chaque objet de base de données, car l'ensemble de pages peut devenir trop volumineux.

Regardez comme ça ... vous ne voulez pas de nouvelles routes; vous voulez ajouter des URL aux itinéraires existants. Si vous ajoutez une route, cela signifie que vous souhaitez qu'une URL mappe vers une fonction distincte. Mais vous mappez chaque URL à la même fonction. Essentiellement, vous ajoutez uniquement des itinéraires par effet secondaire. Ce qui vous importe, c’est qu’un ensemble dynamique d’URL mappe une fonction spécifique.

Pouvez-vous utiliser un caractère générique pour mapper le modèle d’URL à une fonction spécifique, telle que

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

Et gérez le mappage pagesfromdb en dehors de la couche express. Vous pouvez utiliser un accès direct à la base de données, un accès en cache + à une base de données ou un rafraîchissement basé sur un minuteur, selon vos besoins.

1
Brandon

L'ajout d'itinéraires peut être fait à la volée, comme mentionné. La suppression peut aussi, étant donné cette fonction:

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

(volé à partir de La suppression d'une route mappée spécifique dans Node.js lors de l'exécution supprime le mappage statique? )

La mise à jour de tels itinéraires rend votre application "dynamique" et créera probablement un problème si vous avez besoin d'un équilibre de charge.

0
Albin