Cannot get request params in express middleware

2020-07-06 08:49发布

问题:

I am not able to read any req.params in my middleware. I have a minimal express web server that looks like

'use strict';

var express = require('express');
var app = express();

//middleware
function userMiddleware(req, res, next) {
  console.log('user came in. Hello ' + req.param('name'));
  next();
}

//register middleware
app.use('/user', userMiddleware)

// routes
app.get('/user/:name', function(req, res) {
  res.send('username : ' + req.params.name);
});

app.listen(3000);
console.log("listening on 3000...");

When I try to hit localhost:3000/user/williams , I expect to see in the log :

user came in. Hello williams

but I see

user came in. Hello undefined

Should I include any other middleware so that the req.params is populated in the middleware ? I'm using express@3.3.4

回答1:

I think app.param() is unconventional in this case and not really intuitive. Since I already had the function representing the middleware, I could do :

//middleware
function userMiddleware(req, res, next) {
  console.log('user came in. Hello ' + req.params.name);
  next();
}

// routes
app.get('/user/:name', userMiddleware, function(req, res) {
  res.send('username : ' + req.params.name);
});


回答2:

EDIT

My answer below is incorrect. You don't actually need json or urlencoded middleware to get route params - they're only needed for req.query and req.body to work. As you're aware (since you're one of the posters there), the link you provided in your comment describes the issue:

https://github.com/strongloop/express/issues/2088

The problem is that you are trying to access route parameters before they exist - middleware runs before routes do. One solution would be to use app.param() as suggested in that link (instead of your userMiddleware):

app.param('name', function(req, res, next, name) {
    console.log('user came in. Hello ' + name);
    next();
});

Note that this will find name parameters in ALL routes so you might want to name the parameter something a bit more specific, like username. You could also check the beginning of req.url if you wanted to narrow it down that way.

BTW Using req.param() as you did in your original code should generally be avoided; to quote from the Express docs: Direct access to req.body, req.params, and req.query should be favoured for clarity - unless you truly accept input from each object.


OLD ANSWER

Leaving it here since it contains info that might be useful in other situations...

I believe you need to add this middleware in order to have GET and POST variables available:

.use(express.json()) //support JSON-encoded bodies
.use(express.urlencoded()) //support URL-encoded bodies

And:

.use(express.methodOverride())

If you also have a need for HTTP verbs such as PUT or DELETE in all browsers.

Instead of json and urlencoded, you could just use bodyparser, but that would be a security vulnerability due to file uploads. See http://andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html. Also, bodyparser is deprecated in Express 4. Note that if you want to support file uploads you'll need to use additional middleware for that (a good option is https://www.npmjs.org/package/multer).



回答3:

The best solution I have come across is to use a router with an all method.

For example:

function middleware(req, res, next) {
  console.log('Parameters - ', req.params)
}

let router = require('express').Router
router.route('/test')
   .all(middleware)
   .get((req, res, next) => {
     // handle route
   })