处理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
minlength
和maxlength
字段,看看我如何设置自定义错误消息,然后检查下面的方法可以访问或发送到前端的错误对象:
// 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(比如required
, minlength
, maxlength
等等)。
如果你想创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)