Express中间件,next和Promises

7

这是一个非常简单的Express路由器,带有处理程序:

router.get('/users/:userId/roles/:roleId', function(req, res, next){
    const roleId = req.params.roleId;
    res.rest.resource = UserModel.findOne({ _id: req.params.userId}).exec().then(function(usr) {
        console.log(req.params.roleId); // => undefined
        console.log(roleId);            // => okay here
        const result = usr.roles.find( role => String(role._id) === String(roleId));
        return result;
    });
    next();
});

当在promise之外的next()中调用时,访问req.params.roleId会返回undefined。这只对一些特殊情况适用。

我了解异步和promise,并且知道在then处理程序之前调用next()。但是req.params.roleId发生了什么?为什么它会变异?中间件通过next()调用时是否得到相同但已变异的req

注意:稍后由中间件使用的res.rest.resource用于构建正确的REST响应。

1个回答

11

代码执行存在一定的不确定性。

某些东西会在next()处理程序中改变角色ID,由于findOne()最终调度到then处理程序需要一些时间,因此该变异已经发生。

如果不了解您的应用程序的更多详细信息,那么看起来这可能是正确的实现方法。

router.get('/users/:userId/roles/:roleId', function(req, res, next) {
    const roleId = req.params.roleId;
    UserModel.findOne({ _id: req.params.userId}).exec().then((usr) => {
        const result = usr.roles.find(role => String(role._id) === String(roleId));
        res.rest.resource = result;
        next(); // <-- only dispatch to next after we find the resource result
    });
});

编辑:

我深入了解了一下。看看这个小例子应用程序:

var express = require('express');
var app = express();

app.use(function (req, res, next) {
    var v = 0 | +new Date();
    console.log("middleware 1 setting foos to ", v);
    req.params.foo = v;
    req.foo = v;
    next();
});

app.use(function (req, res, next) {
    console.log("middleware 2 reading foos and starting timer:", req.params.foo, req.foo);
    setTimeout(function() {
        console.log("middleware 2: foos are now", req.params.foo, req.foo);
    }, 1000);
    next();
});

app.get("/", function(req, res) {
    res.send("params = " + JSON.stringify(req.params) + " and foo = " + req.foo);
});

app.listen(3000);

请求的输出结果为

middleware 1 setting foos to  -902674369
middleware 2 reading foos and starting timer: undefined -902674369
middleware 2: foos are now undefined -902674369
middleware 1 setting foos to  -902673113
middleware 2 reading foos and starting timer: undefined -902673113
middleware 2: foos are now undefined -902673113

浏览器输出为params = {} and foo = -902673113,因此得出结论您不允许触及req.params,但您可以向req对象添加任何其他属性,它们将正常传递。

这似乎是由于路由匹配层在每个步骤上重写params导致的。


2
为什么不把next()放在Promise链中的finally()里面?这样可以保证next()调用总是被执行。 - peteb
@AKX 将 next() 与设置 res.rest.resource 结合到 Promise 中似乎是个不错的主意,谢谢。 - Alex Povar
@AKX 你知道 next() 到底是做什么的吗?看起来一旦在当前中间件中调用了 next(),所有可用于该中间件的数据都会变得不安全、可变和不可访问。 - Alex Povar
@AlexPovar next() 只是将控制权转交给链中的下一个中间件或处理程序... 但是可以看一下我添加的示例 :) - AKX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接