node.js - 使用 Express.js 的动态路由——这甚至可能吗?

标签 node.js mongodb

每次我用新菜单项更新数据库时,我都试图让路由更新为多一条路由。这是我可悲的 clown 尝试:

在 app.js 中,我检查菜单数据库和 shazaam...路由是在 启动时 动态生成的。酷!:

// in app.js //
var attachDB = function(req, res, next) {
    req.contentdb = db.content;
    req.menudb = db.menu;
    req.app = app;  // this is the express() app itself
    req.page = PageController;
    next();
};
db.menu.find({}, function (err, menuitems){ 
    for(var i=0; record = menuitems[i]; i++) {
        var menuitem = record.menuitem;
        app.all('/' + menuitem, attachDB, function(req, res, next) {
            console.log('req from app all route: ',req)
            PageController.run(menuitem, req, res, next);
        }); 
    }

    http.createServer(app).listen(config.port, function() {
        console.log(
            '\nExpress server listening on port ' + config.port
        );
    });
});

不是很优雅,但它是一个概念证明。现在的问题是:当我在我的 Admin.js 文件中保存一个新的菜单项时,数据库得到了更新,路由器似乎得到了更新,但是在单击带有动态创建路线

请求中的许多内容似乎都丢失了,我觉得有一些关于路由、回调的基本知识我不了解,或者这可能只是错误的解决方案。以下是负责在我的 Admin.js 文件中创建新菜单项和创建新路由的函数:

// in Admin.js //
menuItem: function(req, res, callback) {
    var returnMenuForm = function() {
        res.render('admin-menuitem', {}, function(err, html) {
            callback(html);
        });
    };
    var reqMenudb = req.menudb,
        reqContentdb = req.contentdb,
        reqApp = req.app,
        reqPage = req.page;

    if(req.body && req.body.menuitemsubmitted && req.body.menuitemsubmitted === 'yes') {
        var data = { menuitem: req.body.menuitem };
        menuModel.insert( data, function(err) {
            if (err) {
                console.log('Whoa there...',err.message);
                returnMenuForm();
            } else {
                // data is inserted....great. PROBLEM...the routes have not been updated!!!  Attempt that mimics what I do in app.js here...
                reqApp.all('/' + data.menuitem, function(req, res, next) {
                     // the 2 db references below are set with the right values here
                    req.contentdb = reqContentdb;
                    req.menudb = reqMenudb;
                    next();
                }, function(req, res, next) {
                    reqPage.run(data.menuitem, req, res, next);
                });

                returnMenuForm();
            }
        });
    } else {
        returnMenuForm();
    }
},

在管理部分保存数据工作正常。如果您控制台日志 app.routes,它甚至会显示一条非常酷的新路线。然而,在刷新页面并单击新路由应该工作的链接后,我收到了一个未定义的错误。

管理员将数据传递到我的页面 Controller :

// in PageController.js //
module.exports = BaseController.extend({ 
    name: "Page",
    content: null,
    run: function(type, req, res, next) {
        model.setDB(req.contentdb);  /* <-- problem here, req.contentdb is undefined which causes me problems when talking to the Page model */
        var self = this;
        this.getContent(type, function() {
            var v = new View(res, 'inner');
            self.navMenu(req, res, function(navMenuMarkup){
                self.content.menunav = navMenuMarkup;
                v.render(self.content);
            });
        });
    },
    getContent: function(type, callback) {
        var self = this;
        this.content = {}
        model.getlist(function(records) {
            if(records.length > 0) {
                self.content = records[0];
            }
            callback();
        }, { type: type });
    }

最后,错误点在模型中

// in Model.js //
module.exports = function() {

    return {
        setDB: function(db) {
            this.db = db;
        },
        getlist: function(callback, query) {
            this.db.find(query || {}, function (err, doc) { callback(doc) });
        },

最后,上面的 getlist 方法中的“this”未定义,导致页面崩溃。

如果我重新启动服务器,由于我在 app.js 中的动态加载程序,一切都会再次运行。但是在数据库更新后没有办法重新加载路由吗?我在这里的技术不起作用,并且像我在这里所做的那样将主应用程序传递给 Controller ​​是很丑陋的。

最佳答案

我会建议两个更改:

  1. 将此菜单附件移至单独的模块。
  2. 当你在做的时候,做一些缓存。

概念证明菜单数据库功能,与 setTimeout 异步,您将用实际的数据库调用替换它。

// menuitems is cached here in this module. You can make an initial load from db instead.
var menuitems = [];
// getting them is simple, always just get the current array. We'll use that.
var getMenuItems = function() {
    return menuitems;
}

// this executes when we have already inserted - calls the callback
var addMenuItemHandler = function(newItem, callback) {
    // validate that it's not empty or that it does not match any of the existing ones
    menuitems.push(newItem);
    // remember, push item to local array only after it's added to db without errors
    callback();
}
// this one accepts a request to add a new menuitem
var addMenuItem = function(req, res) {
    var newItem = req.query.newitem;

    // it will do db insert, or setTimeout in my case
    setTimeout(function(newItem){
        // we also close our request in a callback
        addMenuItemHandler(newItem, function(){
            res.end('Added.');
        });

    }, 2000);
};

module.exports = {
    addMenuItem: addMenuItem,
    getMenuItems: getMenuItems
}

现在你有了一个模块menuhandler.js。让我们构建它并在我们的应用程序中使用它。

var menuHandler = require('./menuhandler');
var app = express();
// config, insert middleware etc here

// first, capture your static routes - the ones before the dynamic ones.
app.get('/addmenuitem', menuHandler.addMenuItem);
app.get('/someotherstaticroute', function(req, res) {
    var menu = menuHandler.getMenuItems();
    res.render('someview', {menu: menu});
});


// now capture everything in your menus.
app.get('/:routename', function(req, res){
    // get current items and check if requested route is in there.

    var menuitems = menuHandler.getMenuItems();
    if(menuitems.indexOf(req.params.routename) !== -1) {
        res.render('myview', {menu: menuitems});
    } else {
        // if we missed the route, render some default page or whatever.
    }
});

app.get('/', function(req, res) {
    // ...
});

现在,如果没有新的更新,您就不会去 db(因为 menuitems 数组始终是最新的),因此您的初始 View 呈现得更快(无论如何,对于 1 db 调用)。

编辑:哦,我刚刚看到你的 Model.js。问题在于 this 指的是您返回的对象:

{
    setDB: function(db) {
        this.db = db;
    },
    getlist: function(callback, query) {
        this.db.find(query || {}, function (err, doc) { callback(doc) });
    }
}

因此,默认情况下没有数据库。由于您在初始页面加载时将某些内容附加到 app,因此您确实得到了一些东西。

但在您当前的更新功能中,您将内容附加到新应用程序 (reqApp = req.app),因此现在您不是在与原始应用程序对话,而是与它的另一个实例对话。而且我认为您的后续请求(更新后)将范围全部混淆,因此与实际的最新数据失去联系。

关于node.js - 使用 Express.js 的动态路由——这甚至可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22032614/

相关文章:

node.js - 无法更新 mongodb 中的单个数据

php - 用于实时 ajax 的 MongoDB?

node.js - 如何在 Windows IIS 中托管 React.js 和 Node.js 应用程序?

node.js - npm 说我有未满足的请求依赖项

node.js - 如何使用 jest 测试类中的函数

mongodb - 如何在Windows中播种Docker容器

r - Mongolite 和在 ObjectId 与字符上使用 $lookup 进行聚合

javascript - 将数据从 Promise then 方法传递到对象方法

node.js - 如何处理 Firebase Cloud Functions 无限循环?

python - Pymongo 失败但不会给出异常(exception)