Node.js中间件组织和参数验证

Node.js中间件组织和参数验证,node.js,express,middleware,connect.js,Node.js,Express,Middleware,Connect.js,我正在构建一个express应用程序,我想知道使用中间件我有多喜欢它。大致上,我想用中间件完成以下工作 完成: 将requestId添加到所有路由 验证请求 检查用户是否有权访问给定资源(除 身份验证) 未完成: A)验证给定路线的参数 B)如果不同路由的中间件不同,则以合理的方式组织中间件, 每条路线通常调用3个中间件 我在一个单独的文件中定义了我的中间件,并将其导入app.js,如下所示: var middleware = require('./middleware'); var r

我正在构建一个express应用程序,我想知道使用中间件我有多喜欢它。大致上,我想用中间件完成以下工作

完成:

  • 将requestId添加到所有路由
  • 验证请求
  • 检查用户是否有权访问给定资源(除 身份验证)
未完成:

  • A)验证给定路线的参数
  • B)如果不同路由的中间件不同,则以合理的方式组织中间件, 每条路线通常调用3个中间件
我在一个单独的文件中定义了我的中间件,并将其导入app.js,如下所示:

var middleware = require('./middleware');
var requestId = middleware.requestId;
var authenticate = middleware.authenticate;
要将其应用于所有路线,我将其添加到express config:

var app = express.createServer();
app.configure(function () {
  app.use(express.logger());
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(requestId); // add requestId to all incoming requests
});
对于路线细节,我将其添加为app.get参数:

var routes = require('./v1/routes');
app.get("/v1/foo", routes.foo);
app.get("/v1/bar", authenticate, routes.bar);

问题A

app.get("/v1/bar", authenticate, validate, routes.bar);

function validate(req,res,next){

//Get all parameters here by req.params and req.body.parameter
//validate them and return.
if(validation_true)
next()
}
我希望有一个中间件,我可以用来检查参数

validate('x','y','z')
对于给定的路线,也可以这样使用:

app.get("/v1/bar", authenticate, validate('x','y','z'), routes.bar);
有什么好办法吗?或者我应该只是在路由定义文件中对每个路由进行验证吗

问题B

<> P>有没有更好的方法来组织和使用我应该考虑的中间件?

更新

我正在寻找一种方法来验证路由之间变化很大的参数。下面的内容显然不起作用——我无法将参数传递到中间件中——但有没有办法定义中间件来实现这一点,并像我上面所说的那样调用它

var validateParams = function (req, res, params, callback) {
  // Make sure the required parameters are in the request
  console.log('checking for params '+params);
  for (var i = 0; i < params.length; i++) {
    var param = params[i];
    if(!(param in req.query)){
      logger.info('cannot find param ['+param+'] in req: '+JSON.stringify(req.query));
      res.writeHead(400, {
        "Content-Type": "application/json"
      });
      var out = {
        "err": "request missing required parameters"
      };
      res.end(JSON.stringify(out));
      return;      
    }
  }
  callback();
}
var validateParams=函数(req、res、参数、回调){
//确保请求中包含所需的参数
console.log('检查参数'+参数);
对于(变量i=0;i
问题A

app.get("/v1/bar", authenticate, validate, routes.bar);

function validate(req,res,next){

//Get all parameters here by req.params and req.body.parameter
//validate them and return.
if(validation_true)
next()
}
问题B

您可以使用中间件,而不必总是调用authenticate和validate来自动调用它们。但这可能会导致混乱,例如,您的中间件将在每次调用时运行,因此对于注册/注册来说,运行authenticate是没有意义的

使用validate,有时您需要验证电子邮件,有时需要验证电话号码。因此两者都不能同时进行

因此,在每次调用中单独使用它们似乎是最好的方法。

您可以使用它们来验证请求的正文、查询、参数、标题和cookie。如果任何配置的验证规则失败,它将以错误响应

var validate = require('express-validation'),
    Joi = require('joi');

app.post('/login', validate({
  body: {
    email: Joi.string().email().required(),
    password: Joi.string().regex(/[a-zA-Z0-9]{3,30}/).required()
  }
}), function(req, res){
    res.json(200);
});
这将检查电子邮件和密码正文参数是否与验证规则匹配

如果验证失败,它将响应以下错误

{
  "status": 400,
  "statusText": "Bad Request",
  "errors": [
    {
      "field": "password",
      "location": "body",
      "messages": [
        "the value of password is not allowed to be empty",
        "the value of password must match the regular expression /[a-zA-Z0-9]{3,30}/"
      ],
      "types": [ "any.empty", "string.regex.base" ]
    }
  ]
}

您还可以检查my repo是否完全集成。

您还可以使用高阶函数(返回函数的函数)。从而传递一个端点特定参数数组以进行检查

module.export = Class RequestValidator {
  static validate(params) {
    return function(req, res, next){
      for(const param of params) {
       validateYourParams here...
       if (validation fails) {
         return next(new Error());
       }
      }
      next();
    }
  }
}
在routeDefinition中,您现在可以调用验证中间件并向其传递特定于路由的参数

const RequestValidator = require('your-validation-middleware');
const controller = require('your-controller');

app.post('/path')
   .RequestValidator.validate(
   [{
    name: 'paramName',
    type: 'boolean'
   },
   {
    name: 'paramName2',
    type: 'string'
   }
   ])
   .Controller.handleRequest;

您需要将req,res传递给您的中间件,以便验证(req,res),然后从那里对其进行操作。通常这比传递预先确定的变量要简单。试着查看express验证器。我没有在中间件中使用它,但它看起来是可能的:对于A,我所看到的是验证不同路由的不同参数集-验证(x),验证(x,y),验证(x,y,z)。是否可以像这样传递参数,或者我只是将参数设置为一个数组,然后像validate(req,res,desiredparams,next)一样传递它……好的,是的。但是我认为您应该创建子函数并在函数内部传递它们。如验证电子邮件(请求正文电子邮件);或者甚至验证所需的参数(desiredparams),对于路由,您应该检查req.params,PS:我就是这样做的。:)我发现req.params、req.query、req.param和req.body在我的应用程序的不同区域都会产生不同的结果。因为他们注定是不同的。req.param('name')可以返回,GET?name=sdf POST name=sdf,url query/user/sdf。不同的用途,请阅读这里