我正在尝试决定如何处理Mongoose中的验证错误。
我使用node-validator定义了自己的验证规则,例如:
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' },
但是,node-validator提供自己的错误消息。如果我使用mongoose-validator Node模块将node-validator直接插入我的模式,那么我可以直接使用这些错误消息:
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')] }
});
required
标志Mongoose允许您根据需要定义字段:
var UserSchema = new Schema({
name: { type: String, required: true }
});
这将生成如下所示的错误消息:
name:
{ message: 'Validator "required" failed for path name',
name: 'ValidatorError',
path: 'name',
type: 'required' } }
感觉好像这些验证器想要您使用其内置错误消息。例如,我想将字段声明为required
,如上所示,但我找不到自定义错误消息的方法。并且mongoose-validator模块直到最近才支持自定义消息,这让我觉得它们在模型级别是反模式。
实施这些验证器的最佳方法是什么?我应该让他们产生自己的错误然后以某种方式解释它们吗?
答案 0 :(得分:30)
在这一点上,购买mongoose如何处理错误似乎是合乎逻辑的。
您不希望模型处理错误消息。表示层(控制器?)应该依靠type
来决定哪个是最好的用户友好消息(i18n考虑)。
还有using a middleware验证可能发生的情况。在这种情况下,将显示给控制器的错误消息是您传递给next()
回调的任何内容。
因此,对于中间件的情况,虽然没有记录,但为了在模型中保持一致的验证API,您应该直接使用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();
});
即使验证错误源自中间件,也可以保证一致的验证错误处理。
要将错误消息正确匹配到类型,我会创建一个枚举,它将充当所有可能类型的静态地图:
// 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);
}
});
});
答案 1 :(得分:8)
我知道验证器插件可能有用,但我认为mongoose验证的东西比它真的很复杂更令人生畏。它从外面看起来确实很复杂,但是一旦你开始撕裂它,它就不那么糟糕了。
如果您查看下面的代码,您将看到一个示例,说明如何使用内置验证器返回自定义错误消息。
您需要做的就是在设置字段时设置第二个参数,并带有您自己的自定义错误消息。
检查下面的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,
dropDups: true,
}, // end username field
},
{
timestamps: true,
},
);
// Export the schema:
module.exports = mongoose.model('User', UserSchema);
以上设置我们的字段以获得自定义错误消息。但是我们如何访问它们或将它们发送到我们的前端?我们可以在服务器控制器中设置以下方法,其响应数据将发送回角度:
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) {
if (err.name == 'ValidationError') {
console.error('Error Validating!', err);
res.status(422).json(err);
} else {
console.error(err);
res.status(500).json(err);
}
})
},
};
如果您运行上面的代码,并且我们的任何mongoose验证器都没有通过,那么错误(err
)对象将被promise中的.catch()
抓取。如果您控制台记录此错误,您将在该对象中看到我们的自定义消息,具体取决于标记的错误。
注意:上面的示例仅用于将自定义验证消息添加到Mongoose拥有的已内置验证中(例如required
,minlength
,maxlength
等等。 / p>
如果要创建更高级的验证,例如针对正则表达式模式验证字段等,则必须创建自定义validator
函数。
请参阅此链接中的“自定义验证程序”部分,以获取有关如何在您的字段上添加验证程序的一个很好的示例:http://mongoosejs.com/docs/validation.html。
注意:您也可以使用“预保存挂钩”和“实例方法”,但这超出了本问题的范围,内置验证器和“自定义验证器”(上述链接)是更容易的路径。
希望这有帮助!
答案 2 :(得分:4)
来自猫鼬: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} });
我的前端处理必需的内容,因此我不希望猫鼬“必需”错误发送给用户,更多的是后端安全卫士。
答案 3 :(得分:2)
您需要问自己的问题是谁首先要导致错误?
如果你的系统中发生了这种情况,你就可以控制它,就像你平时那样让错误点击你,并在你继续进行时清除错误,但我怀疑你正在做一个面向真实的应用程序世界用户,你想要消毒他们的投入。
我建议客户端在将其发送到服务器之前检查输入是否正确,并显示好的帮助消息,例如"您的用户名必须介于x和y字符之间"。
然后在服务器端,您希望在99%的情况下输入将直接来自您的清理客户端,因此您仍然使用您已建议的技术对其进行验证,但如果出现错误,您只需返回一个用户界面的一般错误消息 - 因为您相信您的用户界面会显示帮助消息,因此验证错误必须由错误或黑客攻击引起。
请记住记录所有服务器端验证错误,因为它们可能是严重的错误或有人在寻找漏洞利用。
答案 4 :(得分:2)
警告:自Mongoose 4.1.3起,ValidatorError函数的签名已完全更改,以下信息不再适用:
从Mongoose 3.8.12开始,函数ValidatorError的签名是:
function ValidatorError (path, msg, type, val)
其中type可以是“notvalid”或“required”
例如,如果您的“电子邮件”字段验证会引发验证错误,您只需执行以下操作:
var error = new ValidationError(this);
error.errors.email =
new ValidatorError('email', "Your err message.", 'notvalid', this.email);
答案 5 :(得分:1)
从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)
答案 6 :(得分:1)
请参见hmv软件包,该软件包可帮助您自定义猫鼬错误消息模板,包括唯一的索引错误:
template : {PATH_NAME} must be at least {MIN_LENGTH} characters long
schema : { fullname : { type : String, min : 3, $name : 'Full name' } }
message : Full name must be at least 3 characters long
template : {PATH_NAME} {VALUE} have been used, please choose another
schema : { username : { type : String, unique : true } }
message : username MrBean have been used, please choose another
特别支持本地化,例如越南语:
template : {PATH_NAME} dài ít nhất {MIN_LENGTH} kí tự
schema : { fullname : { type : String, min : 3, $name : 'tên tài khoản' } }
message : Tên tài khoản dài ít nhất 5 kí tự
好的一点是,您只需要自定义消息模板一次,而不用以前的方法自定义每个架构的每个字段。
答案 7 :(得分:0)
您还可以使用joi here。实际上,它对于验证节点应用程序中的架构非常有用。
例如:
const Joi = require("joi");
const validateUser = user => {
const Schema = {
email: Joi.string().email().required(),
name: Joi.string().min(3).max(20).required(),
password: Joi.string().min(8).max(25).required()
}
return Joi.validate(user, Schema);
}
答案 8 :(得分:0)
//我的controller.js或任何路由处理程序文件
//这可以在1行中处理多个架构级别验证
// user object created from model
let user = new Users({
firstName: req.body.firstName,
lastName: req.body.lastName
...
});
// Since the Error response are in <Model Name>:<Schema Name>:<Error Message>, ...
var err = user.validateSync();
if (err && err.message) return res.send(err.message.split(':')[2].split(',')[0]);