admin管理员组

文章数量:1129028

I want to pass some variable from the first middleware to another middleware, and I tried doing this, but there was "req.somevariable is a given as 'undefined'".


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

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

////middleware2
...
some conditions
...
variable = req.somevariable;
...

I want to pass some variable from the first middleware to another middleware, and I tried doing this, but there was "req.somevariable is a given as 'undefined'".


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

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

////middleware2
...
some conditions
...
variable = req.somevariable;
...
Share Improve this question edited May 10, 2023 at 15:33 Jonas 129k100 gold badges326 silver badges405 bronze badges asked Sep 18, 2013 at 14:41 user2791897user2791897 3,3092 gold badges14 silver badges7 bronze badges 2
  • 2 Should work. Unless it's a typo in the question you probably fail because you assign the value to res in middleware1 and try to get it from req in middleware2. – Andreas Hultgren Commented Sep 18, 2013 at 14:44
  • 2 Local variables are available in middleware via req.app.locals expressjs.com/pt-br/api.html#app.locals – Ronnie Smith Commented Dec 24, 2018 at 19:48
Add a comment  | 

10 Answers 10

Reset to default 692

v4.x API docs

This is what the res.locals object is for. Setting variables directly on the request object is not supported or documented. res.locals is guaranteed to hold state over the life of a request.

Quote from the docs:

Use this property to set variables accessible in templates rendered with res.render. The variables set on res.locals are available within a single request-response cycle, and will not be shared between requests.

The locals object is used by view engines to render a response. The object keys may be particularly sensitive and should not contain user-controlled input, as it may affect the operation of the view engine or provide a path to cross-site scripting. Consult the documentation for the used view engine for additional considerations.

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

To retrieve the variable in the next middleware:

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

Attach your variable to the res.locals object, not req.

Instead of

req.somevariable = variable1;

Have:

res.locals.somevariable = variable1;

As others have pointed out, res.locals is the recommended way of passing data through middleware.

I don't think that best practice will be passing a variable like req.YOUR_VAR. You might want to consider req.YOUR_APP_NAME.YOUR_VAR or req.mw_params.YOUR_VAR.

It will help you avoid overwriting other attributes.

The most common pattern for passing variables on to other middleware and endpoint functions is attaching values to the request object req.

In your case, that would mean having middlewares such as these:

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

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

There are many common use cases of this pattern, and it is the standard way of doing it in the express community. See, for example:

  • express.json, which ships with express, previously part of body-parser which follows the same pattern for all request parsing.
  • multer used for parsing multipart data
  • express-jwt
  • express-validator (see code)
  • express-session
  • express-useragent
  • express-pino-logger
  • express-bunyan-logger

It is worth noting that the currently most highly voted answer incorrectly recommends using res.locals for this purpose---which seems to stem from a misreading of the documentation. For that reason, I'll elaborate on why this is not the usual approach to the problem (although it isn't particularly harmful either).

The documentation

As supporting evidence for the res.locals approach being the appropriate one for the case, the now outdated documentation is cited:

An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any). Otherwise, this property is identical to app.locals.

This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on.

Note the framing here: res.locals is for variables only available "to the view(s) rendered during that request" (emphasis added).

That is what res.locals relates to. res.render renders some template file with some given data as well as access to the locals. This was actually more clear in the v2 docs, and we've now updated the current Express documentation to be clearer:

Use this property to set variables accessible in templates rendered with res.render. The variables set on res.locals are available within a single request-response cycle, and will not be shared between requests.

In order to keep local variables for use in template rendering between requests, use app.locals instead.

This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on to templates rendered within the application.

(Emphasis added.)

The guide

Further evidence of extending req being the standard approach is found in the guide on Writing Middleware, which states:

Next, we’ll create a middleware function called “requestTime” and add a property called requestTime to the request object.

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

When this was mentioned in discussion in the answers on this here question, one user responded: "This was the way you'd do it before they added res.locals so might be old docs. res.locals is a namespace specifically for this."

This doesn't track with the history of the codebase, however: locals have been present since v2, which is significantly before e.g. express.json was included in the library, at which point it would have made sense to change the behvaior, if it was indeed correct to save values in res.locals.

Closing notes

Shoutout to @real_ate who wrote in the comments, but was overlooked.

That's because req and res are two different objects.

You need to look for the property on the same object you added it to.

The trick is pretty simple... The request cycle is still pretty much alive. You can just add a new variable that will create a temporary, calling

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

Since you can handle your request in the first middleware

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

In middleware 1 you handle your logic and store your value like below:

req.anyvariable = yourvalue

In middleware 2 you can catch this value from middleware 1 doing the following:

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

As mentioned above, res.locals is a good (recommended) way to do this. See here for a quick tutorial on how to do this in Express.

From https://expressjs.com/en/guide/writing-middleware.html :

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

I had this issue too and to overcome it, I saved the variable in Middelware2 passed from midlleware1. So, the solution based on the original question looks something like this:

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

// middleware1
// ...
req.somevariable = variable1;
next();

// middleware2
// ...
const variable = req.somevariable;

Along with middleware, I also use "utility" functions so I don't need to play with the req/res variables (which kind-of increases complexity).

// for ex. we need a condition based on the headers
const isUserAdmin = async(headers) => {
   const authHeaderValue = headers.authorization;
   // perform logic
   return true; // or false
}

app.get("/hello-world", async(req, res, next) => {
  const isAdmin = await isUserAdmin(req.headers)
  if(isAdmin) {
    res.send("You are admin.")
  } else {
    res.send("You do not have admin access.")
  }
})

Note that isUserAdmin a re-usable function so it can be re-used in any number of request handlers.

Good Luck...

本文标签: javascriptPassing variables to the next middleware using next() in ExpressjsStack Overflow