处理Mongoosevalidation错误 – 在哪里以及如何?

我正在试图决定如何处理Mongoose中的validation错误。

使用节点validation器自定义错误消息

我已经使用节点validation器定义了我自己的validation规则,例如:

UserSchema.path('username') .validate(function (username) { return validator.check(username).notEmpty() }, 'Username cannot be blank') 

这将产生一个如下所示的错误:

  username: { message: 'Validator "Username cannot be blank" failed for path username', name: 'ValidatorError', path: 'username', type: 'Username cannot be blank' }, 

使用mongoosevalidation器

但是,节点validation器提供自己的错误消息。 如果我使用mongoose-validator Node模块将节点validation器直接插入到我的模式中,那么我可以直接使用这些错误消息:

 var UserSchema = new Schema({ name: { type: String, validate: [validate('notEmpty')] } }); 

这将生成一个如下所示的错误消息:

  name: { message: 'Validator "String is empty" failed for path name', name: 'ValidatorError', path: 'name', type: 'String is empty' } } 

我也可以在这里提供一个自定义的错误信息:

 var UserSchema = new Schema({ name: { type: String, validate: [validate({message: 'Name cannot be blank' }, 'notEmpty')] } }); 

mongooserequired标志

Mongoose允许您根据需要定义一个字段:

 var UserSchema = new Schema({ name: { type: String, required: true } }); 

这将生成一个如下所示的错误消息:

  name: { message: 'Validator "required" failed for path name', name: 'ValidatorError', path: 'name', type: 'required' } } 

这个问题

感觉好像这些validation器希望你使用他们的内置错误信息。 例如,我想根据required声明一个字段,但是我找不到一个自定义错误消息的方法。 而mongoosevalidation模块直到最近才支持自定义消息,这使我认为它们在模型层面是反模式。

实现这些validation器的最好方法是什么? 我应该让他们产生自己的错误,然后以某种方式后来解释他们?

在这一点上,买入mongoose如何处理错误似乎是合乎逻辑的。

你不希望你的模型处理错误信息。 表示层(控制器?)应该依赖于type来决定哪个是最好的用户友好的消息来显示(i18n考虑)。

也有使用中间件进行validation的情况。 在这种情况下,将传递给next()callback函数的错误消息将显示在您的控制器上。

因此,对于中间件的情况,虽然没有logging,但为了保持模型中的一致性validationAPI,您应该直接使用Mongoose的Error构造函数:

 var mongoose = require('mongoose'); var ValidationError = mongoose.Error.ValidationError; var ValidatorError = mongoose.Error.ValidatorError; schema.pre('save', function (next) { if (/someregex/i.test(this.email)) { var error = new ValidationError(this); error.errors.email = new ValidatorError('email', 'Email is not valid', 'notvalid', this.email); return next(error); } next(); }); 

这样,即使validation错误源自中间件,也可以保证一致的validationerror handling。

要正确匹配错误消息types,我会创build一个枚举 ,它将作为所有可能types的静态映射:

 // my controller.js var ValidationErrors = { REQUIRED: 'required', NOTVALID: 'notvalid', /* ... */ }; app.post('/register', function(req, res){ var user = new userModel.Model(req.body); user.save(function(err){ if (err) { var errMessage = ''; // go through all the errors... for (var errName in err.errors) { switch(err.errors[errName].type) { case ValidationErrors.REQUIRED: errMessage = i18n('Field is required'); break; case ValidationErrors.NOTVALID: errMessage = i18n('Field is not valid'); break; } } res.send(errMessage); } }); }); 

来自Mongoose: https : //github.com/leepowellcouk/mongoose-validator

错误消息自定义错误消息现在返回到0.2.1,可以通过选项对象进行设置:

validate({message: "String should be between 3 and 50 characters"}, 'len', 3, 50)


我如何实现这一点:

 var emailValidator = [validate({message: "Email Address should be between 5 and 64 characters"},'len', 5, 64), validate({message: "Email Address is not correct"},'isEmail')]; var XXXX = new Schema({ email : {type: String, required: true, validate: emailValidator} }); 

我的前端处理所需的,所以我不希望mongoose“必需”的错误,使其对用户,更多的后端安全警卫。

你需要问自己的问题是谁是首先造成错误的责任?

如果这种情况发生在你的系统中,那么你就可以控制它,只要让错误像往常一样击中你,在你走的时候把错误一扫而空,但是我怀疑你正在做一个面向真实世界用户的应用程序,你想要消毒他们的input。

我build议客户端在将它发送到服务器之前检查input是否正确,并且显示诸如“您的用户名必须在x和y字符之间”这样的好帮手消息。

然后在服务器端,您预期在99%的情况下,input将直接来自您的清理客户端,因此您仍然使用您已经build议的技术来validation它,但是如果出现错误,则只需返回一般错误消息到用户界面 – 因为您相信您的用户界面会显示帮助消息,所以validation错误必须由错误或黑客攻击尝试引起。

请记住logging所有的服务器端validation错误,因为它们可能是严重的错误或寻找漏洞的人。

警告:从Mongoose 4.1.3开始,函数ValidatorError的签名已经完全更改,下面的信息不再适用:

截至Mongoose 3.8.12函数ValidatorError的签名是:

 function ValidatorError (path, msg, type, val) 

types可以是“无效”或“需要”

例如,如果您的“电子邮件”字段validation引发validation错误,您可以简单地执行:

 var error = new ValidationError(this); error.errors.email = new ValidatorError('email', "Your err message.", 'notvalid', this.email); 

我知道validation器插件可能是有帮助的,但我认为mongoosevalidation的东西比真的更复杂。 从外面来看,这绝对看起来很复杂,但是一旦你开始撕裂它,那就不是那么糟糕了。

如果您查看下面的代码,您将看到一个如何使用内置validation器返回自定义错误消息的示例。

您只需设置第二个参数,并在设置字段时使用您自己的自定义错误消息。

检查下面required minlengthmaxlength字段,看看我如何设置自定义错误消息,然后检查下面的方法可以访问或发送到前端的错误对象:

 // Grab dependencies: var mongoose = require('mongoose'); // Setup a schema: var UserSchema = new mongoose.Schema ( { username: { type: String, minlength: [2, 'Username must be at least 2 characters.'], maxlength: [20, 'Username must be less than 20 characters.'], required: [true, 'Your username cannot be blank.'], trim: true, unique: true, // username must be unique dropDups: true, }, // end username field }, { timestamps: true, }, ); // Export the schema: module.exports = mongoose.model('User', UserSchema); 

以上设置我们的领域有自定义的错误信息。 但是,我们如何访问它们或将它们发送到我们的前端? 我们可以在我们的服务器控制器中设置以下方法,其响应数据被发送回angular度:

 var myControllerMethods = { register : function(req, res) { // Create a user based on the schema we created: User.create(req.body) .then(function(newUser) { console.log('New User Created!', newUser); res.json(newUser); }) .catch(function(err) { console.log('Error Validating!', err); res.status(500).json(err); }) }, }; 

如果你运行上面的代码,并且我们的任何一个mongoosevalidation器都没有通过,错误( err )对象将被.catch()抓住。 如果您控制台logging了这个错误,那么您将在该对象中看到我们的自定义消息,具体取决于标记了哪个错误。

注意:上面的例子只是添加自定义validation消息到Mongoose拥有的已经内置的validation(比如requiredminlengthmaxlength等等)。

如果你想创build更高级的validation,例如validation正则expression式模式或类似的字段,那么你将不得不创build自定义的validator函数。

请参阅此链接中的“自定义validation器”部分,以获取如何将validation器权限添加到您的字段的示例: http : //mongoosejs.com/docs/validation.html 。

注意:你也可以使用“预保存钩子”和“实例方法”,但是这超出了这个问题的范围,内置的validation器和“自定义validation器”(上述链接)是更简单的路线。

希望这可以帮助!

截至mongoose 4.5.0 Document#invalidate返回一个ValidationError。 看到这个https://github.com/Automattic/mongoose/issues/3964

另外,当试图在findOneAndUpdate查询挂钩上失效时,你可以这样做:

 // pass null because there is no document instance let err = new ValidationError(null) err.errors[path] = new ValidatorError({ path: 'postalCode', message: 'postalCode not supported on zones', type: 'notvalid', value, }) throw(err)