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
每一步。
有一个非常简单的带有处理程序的 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
每一步。