【问题标题】:Node.js middleware organization and parameter validationNode.js 中间件组织和参数验证
【发布时间】:2012-09-23 02:25:08
【问题描述】:

我正在构建一个 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

我很想拥有可以用来检查参数的中间件

validate('x','y','z')

并像这样对给定的路线使用它:

app.get("/v1/bar", authenticate, validate('x','y','z'), routes.bar);

有什么好办法吗?或者我应该只在路由定义文件中基于每个路由进行验证?

问题 B

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

更新

我正在寻找一种方法来验证路由之间变化很大的参数。下面显然不起作用-我不能将参数传递给中间件-但是有没有办法可以定义中间件来执行此操作并按照我上面所说的那样调用它?

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();
}

【问题讨论】:

  • 你需要将 req, res 传递给你的中间件,所以 validate(req, res) 然后从那里开始操作。通常这比传入预先确定的变量要简单。
  • 尝试查看 express-validator。我没有在中间件中使用过,但看起来可以:github.com/ctavan/express-validator

标签: node.js express middleware connect.js


【解决方案1】:

问题 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

您可以使用中间件,而您并不总是需要调用身份验证和验证它们是自动调用的。但这可能会导致混乱,例如。然后,您的中间件将在每次调用时运行,因此对于 SIGNUP/REGISTER,运行身份验证毫无意义。

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

因此,在每次通话中单独使用它们对我来说似乎是最好的方式。

【讨论】:

  • 对于 A,我正在研究为不同的路由验证不同的参数集 - validate(x)、validate(x,y)、validate(x,y,z)。是否可以像这样传递参数,或者我只是将参数设置为一个数组并像 validate(req,res,desiredparams,next) 一样传递它...
  • 嗯,是的。但我认为你应该制作 SUB 函数并将它们传递到函数 validate 中。像 validate_email(req.body.email);甚至 validate_desired(desiredparams) ,对于路线,您应该检查 req.params ,PS:我就是这样做的。 :)
  • 我发现 req.params、req.query、req.param 和 req.body 在我的应用程序的不同区域都会产生不同的结果。
  • 显然。 因为它们注定是不同的。 req.param('name') 可以返回 , GET ?name=sdf POST name=sdf , url 查询 /user/sdf 。不同用途,看这里expressjs.com/api.html
【解决方案2】:

您可以使用express-validation 来验证请求的正文、查询、参数、标头和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" ]
    }
  ]
}

您也可以查看我的 repo express-mongoose-es6-rest-api 以获得完整的集成。

【讨论】:

    【解决方案3】:

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

    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;
    

    【讨论】:

    • 这个解决方案看起来更好并且可重复使用
    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 2019-10-29
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 2018-08-24
    • 2021-03-13
    相关资源
    最近更新 更多