node.js 处理 Mongoose 验证错误——在哪里以及如何处理?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15012250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 13:40:04  来源:igfitidea点击:

Handling Mongoose validation errors – where and how?

node.jsvalidationmongodbmongoose

提问by

I'm trying to decide how I want to handle validation errors in Mongoose.

我正在尝试决定如何处理 Mongoose 中的验证错误。

Custom error messages using node-validator

使用节点验证器的自定义错误消息

I have defined my own validation rules using node-validator, for example:

我已经使用node-validator定义了我自己的验证规则,例如:

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

Which will generate an error that looks like this:

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

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

Using mongoose-validator

使用猫鼬验证器

However, node-validator provides its own error messages. If I use the mongoose-validatorNode module to plug node-validator directly into my schema, then I can use these error messages directly instead:

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

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

Which will generate an error message that looks like:

这将生成一条错误消息,如下所示:

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

I can also provide a custom error message here too:

我也可以在此处提供自定义错误消息:

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

Mongoose requiredflag

猫鼬required

Mongoose lets you define a field as required:

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

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

Which will generate an error message that looks like:

这将生成一条错误消息,如下所示:

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

The question

问题

It feels as if these validators wantyou to use their built-in error messages. For instance, I want to declare a field as requiredas seen above, but I can't find a way of customising the error message. And the mongoose-validator module did not support custom messages up until very recently, which makes me think they are an anti-pattern at the model level.

感觉好像这些验证器希望您使用它们的内置错误消息。例如,我想声明一个required如上所示的字段,但我找不到自定义错误消息的方法。并且 mongoose-validator 模块直到最近才支持自定义消息,这让我认为它们是模型级别的反模式。

What's the best way to implement these validators? Should I let them generate their own errors and then somehow interpret them afterwards?

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

回答by thanpolas

At this point it seems logical to buy in to how mongoose handles errors.

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

You would not want your models to handle error messages. The presentation layer (controllers?) should rely on the typeto decide on which is the best user-friendly message to display (i18n considered).

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

There's also the case where validation may happen by using a middleware. In this case, the error message that will surface up to your controller is whatever you pass to the next()callback.

也有可能通过使用中间件进行验证的情况。在这种情况下,将出现在您的控制器上的错误消息是您传递给next()回调的任何内容。

So, for the case of middleware, although not documented, in order to keep a consistent validation API across your models you should directly use Mongoose's Error constructors:

因此,对于中间件,虽然没有记录,但为了在您的模型中保持一致的验证 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();
});

That way you are guaranteed a consistent validation error handling even if the validation error originates from a middleware.

这样即使验证错误源自中间件,您也可以保证一致的验证错误处理。

To properly match error messages to types I'd create an enumwhich would act as a static map for all possible 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);

    }
  });
});

回答by twknab

I know the validator plugins are probably helpful, but I think the mongoose validation stuff is more intimidating than it really is complicated. It definitely looks complicated from the outside but once you start tearing into it, it's not so bad.

我知道验证器插件可能会有所帮助,但我认为猫鼬验证的东西比它真正复杂的更令人生畏。它从外面看起来肯定很复杂,但是一旦你开始撕扯它,它并没有那么糟糕。

If you check out the code below, you'll see an example of how a custom error message can be returned using built-in validators.

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

All you have to do is set a second parameter, with your own custom error message, when setting up your fields.

您所要做的就是在设置字段时使用您自己的自定义错误消息设置第二个参数。

Checkout the requiredand minlengthand maxlengthfields below to see how I've setup a custom error message, and then check out the methods below as to how the error object can be accessed or sent to the front end:

查看下面的requiredminlengthmaxlength字段以了解我如何设置自定义错误消息,然后查看以下有关如何访问错误对象或将其发送到前端的方法:

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

The above sets up our fields to have custom error messages. But how do we access them or send them to our front end? We could have the following method setup in our server controller, whose response data is sent back to angular:

以上设置了我们的字段以具有自定义错误消息。但是我们如何访问它们或将它们发送到我们的前端?我们可以在我们的服务器控制器中设置以下方法,其响应数据被发送回 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) {
                if (err.name == 'ValidationError') {
                    console.error('Error Validating!', err);
                    res.status(422).json(err);
                } else {
                    console.error(err);
                    res.status(500).json(err);
                }
            })
    },
};

If you ran the code above, and any of our mongoose validators did not pass, the error (err) object will be grabbed by the .catch()in the promise. If you console log this error, you'll see in that object is our custom message, depending upon which error got flagged.

如果您运行上面的代码,并且我们的任何猫鼬验证器没有通过,错误 ( err) 对象将被.catch()承诺中的抓取。如果您控制台记录此错误,您将在该对象中看到我们的自定义消息,具体取决于标记的错误。

Note: The above example is just for adding custom validation messages to the already built-in validations that Mongoose possesses (like required, minlength, maxlengthand so forth).

注:以上例子只是为了添加自定义的验证消息已经内置验证是猫鼬拥有(如requiredminlengthmaxlength等等)。

If you want to create more advanced validations, such as validating fields against regex patterns or the like, then you'll have to create custom validatorfunctions.

如果要创建更高级的验证,例如根据正则表达式模式验证字段等,则必须创建自定义validator函数。

See the "Custom Validators" section at this link for a great example of how to add a validator right onto your field: http://mongoosejs.com/docs/validation.html.

有关如何将验证器直接添加到您的字段的一个很好的示例,请参阅此链接中的“自定义验证器”部分:http: //mongoosejs.com/docs/validation.html

Note: You can also use "pre save hooks" and "instance methods", but this is beyond the scope of this question and the built in validators and "Custom Validators" (link aforementioned) are easier routes.

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

Hope this helps!

希望这可以帮助!

回答by Matt Ritz

From Mongoose: https://github.com/leepowellcouk/mongoose-validator

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

Error Messages Custom error messages are now back in 0.2.1 and can be set through the options object:

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

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

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



How I implemented this:

我是如何实现的:

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

My front end deals with required, so I don't ever expect the mongoose "required" error to make it to the user, more of a back end safe guard.

我的前端处理必需的,所以我从不期望猫鼬的“必需”错误会出现在用户面前,更多的是后端安全保护。

回答by ExxKA

The question you need to ask yourself is who is responsible for causing the error in the first place?

您需要问自己的问题是谁首先对导致错误负责?

If this happens in your system, that you are in control over, just let the errors hit you like you normally would, and weed the bugs out as you go along, but I suspect you are doing an application which is facing real world users and you want to sanitize their inputs.

如果这种情况发生在您的系统中,您可以控制,就让错误像往常一样打击您,并在进行过程中清除错误,但我怀疑您正在开发一个面向现实世界用户的应用程序,并且你想净化他们的输入。

I would recommend that client side you check that the input is correct before you send it to your server, and you show nice helper messages like "Your username must be between x and y characters".

我建议客户端在将输入发送到服务器之前检查输入是否正确,并显示不错的帮助消息,例如“您的用户名必须介于 x 和 y 字符之间”。

Then on the server side you expect that in 99% of the cases the input will come directly from your sanitizing client, and so you still validate it using the techniques you already suggested, but if there is an error you simply return a general error message to the user interface - since you trust that your user interface would have shown helper messages so the validation error must be caused by a bug or a hacking attempt.

然后在服务器端,您希望在 99% 的情况下输入将直接来自您的消毒客户端,因此您仍然使用您已经建议的技术对其进行验证,但是如果出现错误,您只需返回一般错误消息到用户界面 - 由于您相信您的用户界面会显示帮助消息,因此验证错误必须由错误或黑客尝试引起。

Remember to log all server side validation errors as they could be severe bugs or someone looking for exploits.

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

回答by salihcenap

Warning: As of Mongoose 4.1.3 the signature for function ValidatorError has completely changed and the information below is no more applicable:

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

As of Mongoose 3.8.12 the signature for function ValidatorError is:

从 Mongoose 3.8.12 开始,函数 ValidatorError 的签名是:

function ValidatorError (path, msg, type, val) 

Where type can be either "notvalid" or "required"

其中类型可以是“无效”或“必需”

For example if your "email" field validation raises a validation error, you can simply do:

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

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

回答by ztrange

As of mongoose 4.5.0 Document#invalidate returns a ValidationError. See this https://github.com/Automattic/mongoose/issues/3964

从 mongoose 4.5.0 Document#invalidate 开始返回 ValidationError。看到这个 https://github.com/Automattic/mongoose/issues/3964

Also, when trying to invalidate on a findOneAndUpdate query hook, you can do:

此外,当尝试使 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)

回答by Dinh Hoang

See the hmvpackage, which helps you customize the mongoose error message templates, including unique index errors :

查看hmv包,它可以帮助您自定义 mongoose 错误消息模板,包括唯一索引错误:

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

And specifically supports localization, ex in Vietnamese :

并且特别支持本地化,例如越南语:

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?

Good point is that you only need to customize the message template once, instead of customizing every field of every schema in the previous approach.

好处是您只需要自定义一次消息模板,而不是在前面的方法中自定义每个模式的每个字段。

回答by Ravi Singh

you can also use joi here. It is actually very useful package for validating the schema in node app.

你也可以在这里使用 joi 。它实际上是用于验证节点应用程序中架构的非常有用的包。

for eg:

例如:

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

}

回答by brooks

// my controller.js or whatever your route handler file is
// This Handles multiple Schema Level Validations in 1 line

// 我的 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]);