在Express.js中使用next()将变量传递给下一个中间件

我想通过一些变量从第一个中间件到另一个中间件,我试着这样做,但有&;req.somevariable是一个给定为“未定义”&;


//app.js
..
app.get('/someurl/', middleware1, middleware2)
...

////middleware1
...
some conditions
...
res.somevariable = variable1;
next();
...

////middleware2
...
some conditions
...
variable = req.somevariable;
...
208990 次浏览

这是因为reqres是两个不同的对象。

您需要在将属性添加到的同一对象上查找该属性。

将变量附加到req对象,而不是res对象。

而不是

req.somevariable = variable1;

有:

res.locals.somevariable = variable1;

正如其他人指出的那样,res.locals是通过中间件传递数据的推荐方式。

我不认为最好的做法是传递像req.YOUR_VAR这样的变量。你可能想要考虑req.YOUR_APP_NAME.YOUR_VARreq.mw_params.YOUR_VAR

它将帮助您避免覆盖其他属性。

v1 API 文档

这就是res.locals对象的作用。不支持直接在请求对象上设置变量,也没有相关文档。res.locals保证在请求的整个生命周期内保持状态。

引用文件:

对象的响应局部变量 请求,因此仅对期间呈现的视图可用 请求/响应周期(如果有的话)。否则,这个属性为 与app.locals相同。

此属性用于公开请求级信息,例如 请求路径名,认证用户,用户设置,等等

app.use(function(req, res, next) {
res.locals.user = req.user;
res.locals.authenticated = !req.user.anonymous;
next();
});

在下一个中间件中检索变量:

app.use(function(req, res, next) {
if (res.locals.authenticated) {
console.log(res.locals.user.id);
}
next();
});

v2 API 文档

在express的版本2中,res.locals已从v1中看到的字典样式对象更改为名为res.local的getter / setter函数和名为res.locals的批量对象setter函数。

按键设置局部变量:

res.local("user", { name: "Jim" });

按键获取一个局部变量:

const user = res.local("user");


console.log(user);
// { name: "Jim" }

一次性批量设置所有本地响应状态:

const state = {
user: {
name: "Jim"
}
};


res.locals(state);

除了转移到功能更丰富的API之外,用例并没有改变。

诀窍很简单……请求周期仍然存在。您只需添加一个新变量,它将创建一个临时的调用

app.get('some/url/endpoint', middleware1, middleware2);

因为您可以在第一个中间件中处理请求

(req, res, next) => {
var yourvalue = anyvalue
}

在中间件1中,你可以像下面这样处理你的逻辑并存储你的值:

req.anyvariable = yourvalue

在中间件2中,你可以通过以下方法从中间件1中获取这个值:

(req, res, next) => {
var storedvalue = req.yourvalue
}

如上所述,res.locals是一种很好的(推荐的)方法。有关如何在Express中执行此操作的快速教程,请参阅在这里

将变量传递给其他中间件和端点函数的最常见模式是将值附加到请求对象req

在你的例子中,这意味着有这样的中间件:

app.use(function (req, res, next) {
req.someVariable = 123;
next();
});


app.use(function (req, res, next) {
console.log("The variable is", req.someVariable);
next();
});

此模式有许多常见的用例,并且它是在express社区中执行此操作的标准方式。例如:


值得注意的是,目前投票最高的答案错误地建议为此使用res.locals——这似乎源于对文档的误读。出于这个原因,我将详细说明为什么这不是解决问题的通常方法(尽管它也不是特别有害)。

的文档

作为支持res.locals方法适合这种情况的证据,引用了现在过时文档:

一个包含响应局部变量的对象,其作用域为请求,因此仅对在请求/响应周期(如果有的话)期间呈现的视图可用。否则,此属性与app.locals相同。

此属性对于公开请求级信息(如请求路径名称、经过身份验证的用户、用户设置等)非常有用。

注意这里的框架:res.locals只适用于变量"到在请求期间呈现的视图"(强调)。

这就是res.locals所关联的。res.render将包含给定数据的模板文件呈现给局部变量。这实际上在v2文档中更清楚,而我们已经更新了现行快递文件更清楚:

res.locals上设置的变量在单个请求-响应周期内可用,并且不会在请求之间共享。

为了在请求之间的模板渲染中保留局部变量,请使用app.locals。

此属性对于公开请求级信息非常有用,例如请求路径名称、已验证用户、用户设置等到应用程序中呈现的模板。

(强调)。

该指南

req扩展为标准方法的进一步证据可以在关于< em >编写中间件< / em >的指南中找到,该指南指出:

接下来,我们将创建一个名为“requestTime”的中间件函数,并向请求对象添加一个名为requestTime的属性。

const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}

当在回答这个问题的讨论中提到这一点时,一个用户回答说:“在他们添加res.locals之前,这就是你的做法,所以可能是旧文档。”Res.locals是一个专门用于这个。"

然而,这与代码库的历史并不一致:局部变量一直是从v2开始,这在例如express.json被包含在库中之前非常重要,在这一点上,如果在res.locals中保存值确实正确,那么改变行为是有意义的。

关闭笔记

喊出@real_ate在评论中写道,但被忽视。