Express 中间件、next 和 Promises

Express middleware, next and Promises

有一个非常简单的带有处理程序的 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 中访问 req.params.roleId 会返回 undefined。这仅适用于 next() 调用外部承诺的 then 的情况。

我同意异步和承诺,并且理解 next() 将在 then 中的处理程序之前被调用。但是 req.params.roleId 发生了什么?为什么以及在哪里发生变异? next() 调用的中间件是否相同但发生了变异 req

注意:res.rest.resource 被稍后调用的中间件用来构建正确的类似 REST 的响应。

代码在其执行过程中存在不确定性。

Something 改变了 next() 处理程序中的角色 ID,并且由于 findOne() 需要一段时间才能最终分派到 then handler,突变已经发生了

在不知道您的应用的更多详细信息的情况下,这看起来可能是正确的实现。

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每一步。