app.param([name], callback)

给路由参数添加回调触发器,这里的name是参数名或者参数数组,function是回调方法。回调方法的参数按序是请求对象,响应对象,下个中间件,参数值和参数名。
如果name是数组,会按照各个参数在数组中被声明的顺序将回调触发器注册下来。还有,对于除了最后一个参数的其他参数,在他们的回调中调用next()来调用下个声明参数的回调。对于最后一个参数,在回调中调用next()将调用位于当前处理路由中的下一个中间件,如果name只是一个string那就和它是一样的(就是说只有一个参数,那么就是最后一个参数,和数组中最后一个参数是一样的)。
例如,当:user出现在路由路径中,你可以映射用户加载的逻辑处理来自动提供req.user给这个路由,或者对输入的参数进行验证。

  1. app.param('user', function(req, res, next, id) {
  2. User.find(id, function(error, user) {
  3. if (err) {
  4. next(err);
  5. }
  6. else if (user){
  7. req.user = user;
  8. } else {
  9. next(new Error('failed to load user'));
  10. }
  11. });
  12. });

对于Param的回调定义的路由来说,他们是局部的。它们不会被挂载的app或者路由继承。所以,定义在app上的Param回调只有是在app上的路由具有这个路由参数时才起作用。
在定义param的路由上,param回调都是第一个被调用的,它们在一个请求-响应循环中都会被调用一次并且只有一次,即使多个路由都匹配,如下面的例子:

  1. app.param('id', function(req, res, next, id) {
  2. console.log('CALLED ONLY ONCE');
  3. next();
  4. });
  5. app.get('/user/:id', function(req, res, next) {
  6. console.log('although this matches');
  7. next();
  8. });
  9. app.get('/user/:id', function(req, res) {
  10. console.log('and this mathces too');
  11. res.end();
  12. });

GET /user/42,得到下面的结果:

  1. CALLED ONLY ONCE
  2. although this matches
  3. and this matches too
  1. app.param(['id', 'page'], function(req, res, next, value) {
  2. console.log('CALLED ONLY ONCE with', value);
  3. next();
  4. });
  5. app.get('/user/:id/:page', function(req. res, next) {
  6. console.log('although this matches');
  7. next();
  8. });
  9. app.get('/user/:id/:page', function (req, res, next) {
  10. console.log('and this matches too');
  11. res.end();
  12. });

当执行GET /user/42/3,结果如下:

  1. CALLED ONLY ONCE with 42
  2. CALLED ONLY ONCE with 3
  3. although this matches
  4. and this mathes too

下面章节描述的app.param(callback)在v4.11.0之后被弃用。

通过只传递一个回调参数给app.param(name, callback)方法,app.param(naem, callback)方法的行为将被完全改变。这个回调参数是关于app.param(name, callback)该具有怎样的行为的一个自定义方法,这个方法必须接受两个参数并且返回一个中间件。
这个回调的第一个参数就是需要捕获的url的参数名,第二个参数可以是任一的JavaScript对象,其可能在实现返回一个中间件时被使用。
这个回调方法返回的中间件决定了当URL中包含这个参数时所采取的行为。
在下面的例子中,app.param(name, callback)参数签名被修改成了app.param(name, accessId)。替换接受一个参数名和回调,app.param()现在接受一个参数名和一个数字。

  1. var express = require('express');
  2. var app = express();
  3. app.param(function(param, option){
  4. return function(req, res, next, val) {
  5. if (val == option) {
  6. next();
  7. }
  8. else {
  9. res.sendStatus(403);
  10. }
  11. }
  12. });
  13. app.param('id', 1337);
  14. app.get('/user/:id', function(req, res) {
  15. res.send('Ok');
  16. });
  17. app.listen(3000, function() {
  18. console.log('Ready');
  19. });

在这个例子中,app.param(name, callback)参数签名保持和原来一样,但是替换成了一个中间件,定义了一个自定义的数据类型检测方法来检测user id的类型正确性。

  1. app.param(function(param, validator) {
  2. return function(req, res, next, val) {
  3. if (validator(val)) {
  4. next();
  5. }
  6. else {
  7. res.sendStatus(403);
  8. }
  9. }
  10. });
  11. app.param('id', function(candidate) {
  12. return !isNaN(parseFloat(candidate)) && isFinite(candidate);
  13. });

在使用正则表达式来,不要使用.。例如,你不能使用/user-.+/来捕获user-gami,用使用[\\s\\S]或者[\\w\\>W]来代替(正如/user-[\\s\\S]+/)。

  1. //captures '1-a_6' but not '543-azser-sder'
  2. router.get('/[0-9]+-[[\\w]]*', function);
  3. //captures '1-a_6' and '543-az(ser"-sder' but not '5-a s'
  4. router.get('/[0-9]+-[[\\S]]*', function);
  5. //captures all (equivalent to '.*')
  6. router.get('[[\\s\\S]]*', function);