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

use*_*897 161 javascript middleware next node.js express

好吧,我的问题是我想将一些变量从第一个中间件传递到另一个中间件,我尝试这样做,但是" req.somevariable有一个给定为'undefined'".


//app.js
..
app.get('/someurl/', middleware1, middleware2)
...
Run Code Online (Sandbox Code Playgroud)
////middleware1
...
some conditions
...
res.somevariable = variable1;
next();
...
Run Code Online (Sandbox Code Playgroud)
////middleware2
...
some conditions
...
variable = req.somevariable;
...
Run Code Online (Sandbox Code Playgroud)

cch*_*ain 347

这就是res.locals对象的用途.不支持或记录直接在请求对象上设置变量.res.locals保证在请求的整个生命周期内保持状态.

res.locals

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

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

app.use(function(req, res, next) {
    res.locals.user = req.user;  
    res.locals.authenticated = !req.user.anonymous;
    next();
});
Run Code Online (Sandbox Code Playgroud)

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

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

  • 不知道为什么这不是公认的答案,这是_**记录**_在整个请求中从中间件设置变量的方法. (55认同)
  • res.locals旨在由**视图**使用,这些视图最终在请求的生命周期中呈现,这就是文档所说的内容.如果你没有使用视图,那么将东西放在locals对象上是不合适的,它不是*惯例.在这些情况下,我倾向于鼓励人们坚持使用惯例,这样我们就可以在学习Express或请求生命周期等概念的同时减少认知负担. (10认同)
  • 编写中间件的快速文档在`req`对象https://expressjs.com/en/guide/writing-middleware.html上设置变量.查看`Middleware function requestTime`部分 (9认同)
  • 这是在他们添加 `res.locals` 之前您执行此操作的方式,因此可能是旧文档。`res.locals` 是专门用于此目的的命名空间。由于存在保留的属性和不断变化的标准,改变请求可能是危险的。 (5认同)
  • @goonerify 幸运的是,这不是响应的工作原理。响应是通过调用响应对象的功能属性(例如“res.json({})”等)来传输的。“res.locals”仅在请求的生命周期内在后端可用。https://expressjs.com/en/5x/api.html (3认同)
  • @real_ate是res.locals的主要用法,但它没有解决OP问题.将请求范围变量传递给未来的中间件有时是必要的,我提出它的时间通常是在早期中间件中进行用户身份验证,该中间件设置在下游中间件中路由的声明. (2认同)
  • 它仍然有效,因为有太多中间件库不为您提供 res 对象。几乎每次我需要这样做时,“res.locals”都是不可能的。`multer` 和 `express-http-proxy` 是两个突出的例子。因此,我认为 @real_ate 的评论一针见血。 (2认同)
  • 我在“标记正确”的答案中说了这一点,但我也会在这里添加它:推荐 `res.locals` 在哪里?你们一直参考的 API 文档似乎表明 res.locals 字段用于在使用“res.render”时将数据传递到视图。事实上,像`express.json()`这样的中间件扩展了`req`,这似乎与这里给出的建议相矛盾? (2认同)

Amb*_*mps 167

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

代替

res.somevariable = variable1;
Run Code Online (Sandbox Code Playgroud)

有:

req.somevariable = variable1;
Run Code Online (Sandbox Code Playgroud)

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

  • 使用res.locals.variable = var; 看到另一个答案 (9认同)
  • `res.locals` 推荐在哪里?你们一直参考的 API 文档似乎表明 res.locals 字段用于在使用“res.render”时将数据传递到视图。事实上,像`express.json()`这样的中间件扩展了`req`,这似乎与这里给出的建议相矛盾? (5认同)
  • 抱歉问了,但现在我很困惑。这是矛盾的答案吗?首先,您建议使用“req.somevariable=variable1;”,然后建议使用“res.locals”。也许我错过了一些东西,如果有人可以更好地解释我吗? (4认同)
  • 要检索变量,请在下一个中间件函数中使用 req.res.locals.variable (3认同)
  • @WilliamWu它的`res.locals`,而不是`req.res.locals`. (3认同)
  • res.locals.myVar是要走的路。 (2认同)

Nie*_*ard 41

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

\n

就您而言,这意味着拥有如下中间件:

\n
app.use(function (req, res, next) {\n  req.someVariable = 123;\n  next();\n});\n\napp.use(function (req, res, next) {\n  console.log("The variable is", req.someVariable);\n  next();\n});\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n\n
\n

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

\n

文档

\n

res.locals作为该方法适合该案例的支持证据,引用了现已过时的文档

\n
\n

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

\n

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

\n
\n

请注意此处的框架:res.locals仅适用于“在该请求期间呈现的视图”可用的变量(添加了强调)。

\n

这就是res.locals相关的。res.render使用一些给定的数据渲染一些模板文件以及对本地数据的访问。这实际上在v2 文档中更加清楚,我们现在更新了当前的 Express 文档以使其更加清晰:

\n
\n

使用此属性可以设置在使用 res.render 渲染的模板中可访问的变量。res.locals 上设置的变量在单个请求-响应周期内可用,并且不会在请求之间共享。

\n

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

\n

此属性对于向应用程序中呈现的模板公开请求级信息(例如请求路径名称、经过身份验证的用户、用户设置等)非常有用。

\n
\n

(强调是添加的。)

\n

导游

\n

扩展成为标准方法的进一步证据可以在编写中间件req指南中找到,其中指出:

\n
\n

接下来,我们\xe2\x80\x99将创建一个名为\xe2\x80\x9crequestTime\xe2\x80\x9d的中间件函数,并向请求对象添加一个名为requestTime的属性。

\n
const requestTime = function (req, res, next) {\n req.requestTime = Date.now()\n next()\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

当在关于此问题的答案的讨论中提到这一点时,一位用户回答道:“这是在添加 res.locals 之前您执行此操作的方式,因此可能是旧文档。res.locals 是专门用于此目的的命名空间”。

\n

然而,这与代码库的历史无关:本地变量自 v2 以来就已经存在,这明显早于将 egexpress.json包含在库中的时间,此时更改行为是有意义的,如果它确实是这样的话正确保存值res.locals

\n

结束语

\n

感谢@real_ate,他在评论中写道,但被忽视了。

\n


Dor*_*gal 21

我不认为最佳实践会传递变量之类的req.YOUR_VAR.你可能想要考虑req.YOUR_APP_NAME.YOUR_VARreq.mw_params.YOUR_VAR.

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

  • 您如何建议最初设置`req.YOUR_APP_NAME = {}`?您只是尝试写入"req.YOUR_APP_NAME.someVar",因为尚未定义"req.YOUR_APP_NAME",您将收到错误消息. (2认同)
  • @Kousha您可以在路由脚本的顶部编写路由器中间件:`router.use(function(req,res,next){req.YOUR_APP_NAME = {}; next()})` (2认同)

SLa*_*aks 6

那是因为req并且res是两个不同的对象.

您需要在添加它的同一对象上查找属性.


Del*_*ino 5

诀窍很简单......请求周期仍然很活跃。您可以添加一个新变量来创建一个临时的,调用

app.get('some/url/endpoint', middleware1, middleware2);
Run Code Online (Sandbox Code Playgroud)

由于您可以在第一个中间件中处理您的请求

(req, res, next) => {
    var yourvalue = anyvalue
}
Run Code Online (Sandbox Code Playgroud)

在中间件 1 中,您处理您的逻辑并存储您的值,如下所示:

req.anyvariable = yourvalue
Run Code Online (Sandbox Code Playgroud)

在中间件 2 中,您可以从中间件 1 中捕获此值,执行以下操作:

(req, res, next) => {
    var storedvalue = req.yourvalue
}
Run Code Online (Sandbox Code Playgroud)