Node.js中间件组织和参数validation

我正在构build一个快速的应用程序,我想知道我可以用中间件获得多大的function。 粗略地说,我想用中间件来完成以下任务。

完成:

  • 将requestId添加到所有路由
  • validation请求
  • 检查用户是否有权访问给定的资源(除了身份validation)

尚未完成:

  • A)validation给定路线的参数
  • B)如果中间件与路由不同,则以合理的方式组织中间件,每个路由按惯例调用3个中间件

我已经在一个单独的文件中定义了我的中间件,并将其导入到app.js中,如下所示:

var middleware = require('./middleware'); var requestId = middleware.requestId; var authenticate = middleware.authenticate; 

要将其应用到所有路线,我将其添加到表示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); 

有没有一个好的方法来做到这一点? 还是应该在路由定义文件中的每个路由基础上进行validation?

问题B

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

更新

我正在寻找一种方法来validation路线之间变化很大的参数。 下面显然不工作 – 我不能将params传递到中间件 – 但是有什么方法可以定义这样做的中间件,并按上面所述调用它?

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

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

您可以使用中间件,而不总是需要调用身份validation并validation它们是否被自动调用。 但是,这可能会导致一个混乱,例如。 那么你的中间件就会在每次调用时运行,所以对于注册/注册来说,没有任何一点运行authentication。

通过validation,有时您需要validation电子邮件,有时电话号码。 所以都不能走。

所以在每次通话中分开使用它们对我来说似乎是最好的方式。

您可以使用快速validation来validation请求的正文,查询,参数,标题和cookie。 如果任何已configuration的validation规则失败,它将以错误响应。

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

这将检查电子邮件和密码主体参数是否符合validation规则。

如果validation失败,它将响应以下错误。

 { "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以获得完整的集成。

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

 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中,您现在可以调用validation中间件并将路由特定的parameter passing给它。

 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;