2012-09-23 42 views
6

我正在構建一個快速應用程序,我想知道我可以用中間件獲得多大的功能。粗略地說,我想用中間件來完成以下任務。Node.js中間件組織和參數驗證

完成:

  • 添加的requestId所有路線
  • 身份驗證請求的用戶
  • 檢查是否有(從 認證分開)訪問給定的資源

未完成:

  • A)對於給定的路由驗證參數
  • B)組織中間件在一個健全的方式,如果它從路線路線不同, 和3中間件例行稱爲每條路線

我已經定義我中間件在一個單獨的文件,將其導入到app.js像這樣:

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

將它應用到我添加它來表達配置的所有路由:

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

問題的

我很想有中間件,我可以用它來檢查參數

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

並使用它像這樣對於給定的路線:

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

有沒有一個很好的方法來做到這一點?或者我應該在路由定義文件中按照每個路由進行驗證?

題B

有沒有更好的方式來組織和使用我的中間件,我應該考慮什麼?

更新

我正在尋找一種方法來驗證更改路線之間的很多參數。下面顯然不起作用 - 我不能將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(); 
} 
+0

您會希望將req,res傳遞給您的中間件,以驗證(req,res),然後從那裏執行操作。通常這比傳遞預定變量更簡單。 – Brandon

+0

嘗試查找express-validator。我沒有用它在中間件,但它看起來有可能:https://github.com/ctavan/express-validator – chovy

回答

2

問題的

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

您可以在一個方式,你並不總是需要調用識別並驗證它們被自動調用使用中間件。但是這可能會導致一團糟,例如。您的中間件然後會在每次通話中運行,因此對於註冊/註冊,沒有任何一點運行身份驗證。

通過驗證,有時您需要驗證電子郵件,有時電話號碼。所以兩個都不能走。

因此,在每次通話時分別使用它們似乎是對我最好的方式。

+0

對於A,我在看什麼驗證不同路由的不同組參數 - validate(x),validate (x,y),驗證(x,y,z)。是否有可能傳遞這樣的參數,或者我只是將參數設置爲一個數組,然後像驗證一樣傳遞它(req,res,desiredparams,next)... – nflacco

+0

嗯,是的。但我認爲你應該製作SUB函數並將它們傳遞給函數驗證。像validate_email(req.body.email);或甚至validate_desired(desiredparams),和路線,你應該檢查req.params,** PS:這是我的方式。** :) –

+0

好吧,這似乎很合理 – nflacco

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" ] 
    } 
    ] 
} 

您還可以檢查我的回購express-mongoose-es6-rest-api完全集成。

1

您也可以使用高階函數(返回函數的函數)。從而傳遞一組特定於端點的參數進行檢查。

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;