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;