Joi 验证仅返回一条错误消息

Posted

技术标签:

【中文标题】Joi 验证仅返回一条错误消息【英文标题】:Joi validation return only one error message 【发布时间】:2014-11-15 05:34:30 【问题描述】:

我有一个由名称字段、电子邮件字段和文本区域组成的三字段表单。我正在使用 Joi 4.7.0 版本和 hapijs。我使用下面的对象验证输入。我从 ajax 调用接收数据对象。当我用错误信息填写所有三个字段时,我只会得到与第一个错误字段相关的消息。像这样:

""statusCode":400,"error":"Bad Request","message":"name is not allowed to be empty","validation":    "source":"payload","keys":["data.name"]"

validate: 
      payload: 
        data: 
          name: Joi.string().min(3).max(20).required(),
          email: Joi.string().email().required(),
          message: Joi.string().min(3).max(1000).required()
        
      

为了解释,假设不填写这三个字段。我只收到一个消息错误,而不是其他字段的消息错误。为什么?

【问题讨论】:

【参考方案1】:

这是因为 Joi 默认提前中止。

abortEarly - 当true 时,对第一个错误停止验证,否则返回找到的所有错误。默认为true

*编辑: hapi 8.0 中的配置已更改。您需要将abortEarly: false 添加到routes 配置中:

var server = new Hapi.Server();
server.connection(
    host: 'localhost',
    port: 8000,
    routes: 
        validate: 
            options: 
                abortEarly: false
            
        
    
);

*有关详细信息,请参阅Joi API documentation。 *另外,请参阅Hapi Route options 下的validation

所以 Joi 在第一个错误时停止验证:

var Hapi = require('hapi');
var Joi = require('joi');

var server = new Hapi.Server('localhost', 8000);

server.route(
    method: 'GET',
    path: '/first/second',
    config: 
        validate: 
            params: 
                first: Joi.string().max(5),
                second: Joi.string().max(5)
            
        
    ,
    handler: function (request, reply) 

        reply('example');
    
);

server.start();

server.inject('/invalid/invalid', function (res) 

    console.log(res.result);
);

输出:

 statusCode: 400,
  error: 'Bad Request',
  message: 'first length must be less than or equal to 5 characters long',
  validation:  source: 'params', keys: [ 'first' ]  

但是,您可以将 Hapi 配置为返回所有错误。为此,您需要将abortEarly 设置为false。您可以在服务器配置中执行此操作:

var server = new Hapi.Server('localhost', 8000,  validation:  abortEarly: false  );

如果你现在运行脚本,你会得到:

 statusCode: 400,
  error: 'Bad Request',
  message: 'first length must be less than or equal to 5 characters long. second length must be less than or equal to 5 characters long',
  validation:  source: 'params', keys: [ 'first', 'second' ]  

【讨论】:

【参考方案2】:

validation 键不再适用于 Hapi 8.0 中的 Hapi.Server 构造函数:

[1] 不允许验证

我在GitHub issue for hapi 中找到了解决方案:

var Hapi = require('hapi');


var server = new Hapi.Server();

server.connection(
  host: HOST,
  port: PORT,
  routes: 
    validate: 
      options: 
        abortEarly: false
      
    
  
);

// Route using Joi goes here.
server.route();

server.start(function () 
  console.log('Listening on %s', server.info.uri);
);

【讨论】:

【参考方案3】:

我没有与 hapi.js 集成,但我注意到有一个可以传递的 ValidationOptions 对象。该对象内部是一个abortEarly 选项,因此应该可以:

Joi.validate(request, schema, abortEarly: false

也可以这样配置:

Joi.object().options( abortEarly: false ).keys(...);

查看这些类型定义以了解更多ValidationOptions: https://github.com/DefinitelyTyped/tsd/blob/master/typings/joi/joi.d.ts

【讨论】:

它在 2020 年仍然可以使用 node v12.18.0 和 hapi 17.1.1,谢谢为我节省了很多时间? 完美运行!【参考方案4】:

经过一番研究,我发现可以通过两种方式解决:

[Segments.BODY]: Joi.object().keys(
value: Joi.string().required().error(new Error('Value is required and has to be a text!')),
)

[Segments.BODY]: Joi.object().keys(
password: Joi.string().required().pattern(new RegExp('^[a-zA-Z0-9]3,30$')).min(8).label('Password').messages(
    'string.pattern.base': 'Your #label does not matche the suggested pattern',
    'string.base': `Your #label should match the suggested pattern`,
    'string.empty': `Your #label can not be empty`,
    'string.min': `Your #label has to be at least #limit chars`,
    'any.required': `Your #label is required`,
),
)

【讨论】:

以上是关于Joi 验证仅返回一条错误消息的主要内容,如果未能解决你的问题,请参考以下文章

如何从控制器方法验证返回自定义错误消息

实体验证后如何获取错误消息

以 JSON 形式返回验证错误消息 - Laravel 6

Foreach 循环仅针对第一组工作人员返回错误消息

为啥验证器方法返回true时会弹出一段时间的错误消息?

导航返回时不清除文本输入并验证错误消息