如何让Joi验证输出警告而非抛出错误?
问题描述
使用Joi包做参数验证时,当传入无效值(比如用数字替代字符串),当前的验证逻辑会抛出错误,阻止事件存入数据库。现在需要调整为仅记录验证错误的警告日志,不中断流程,允许事件正常存入数据库。
当前相关代码如下:
注册命令的Joi Schema
const registerCommandSchema = baseEntitySchema.append({ name: Joi.string().required(), type: Joi.string() .valid(...Object.values(EntityType)) .required(), manualEntry: Joi.boolean().required(), sourceIp: Joi.string().ip().required(), caid: Joi.string(), status: Joi.string().valid(...Object.values(Status)), shortId: Joi.string(), }); export class RegisterCommand extends ICommand<RegisterCommandDto> { schema(): Joi.ObjectSchema { return registerCommandSchema; } }
基础命令抽象类(ICommand)
export abstract class ICommand<Dto> { constructor(public readonly dto: Dto) { } /** * Returns the sub-class specific Joi.ObjectSchema to be used during this.validate() */ abstract schema(): Joi.ObjectSchema; /** * Validate command to ensure there is no invalid field values * e.g. missing properties, invalid values ... etc * Any validation issue => throws an Error. */ validate(): void { const { error } = this.schema().validate(this.dto); if (!error) { return; } throw new ClientError(error.details[0].message); } }
命令处理器
import { IHookAction, HookAction } from '@nestpack/hooks'; import { RegisterCommand } from '../impl'; import { EntityRepository } from '../../repositories/entityRepository'; @HookAction(RegisterCommand) export class RegisterCommandHandler implements IHookAction { constructor(private readonly repository: EntityRepository) {} async handle(command: RegisterCommand) { console.log('RegisterCommandHandler.execute'); console.log(JSON.stringify(command, null, 2)); command.validate(); const { dto } = command; await this.repository.register(dto); } }
解决方案
核心是修改ICommand中的validate方法,移除抛出错误的逻辑,替换为日志记录;同时确保处理器流程不会被中断。
步骤1:修改ICommand的validate方法
将原来抛出ClientError的逻辑,替换为记录警告日志。如果项目中有统一的日志工具(比如你提到的info/warn方法),确保正确引入并使用;如果没有,用console.warn临时替代:
export abstract class ICommand<Dto> { constructor(public readonly dto: Dto) { } abstract schema(): Joi.ObjectSchema; validate(): void { const { error } = this.schema().validate(this.dto); if (!error) { return; } // 替换为项目实际的日志工具,比如logger.warn console.warn(`验证警告:${error.details.map(d => d.message).join('; ')}`); // 如果你的info方法是日志工具的实例方法,确保已注入或正确引用 // 例如:this.logger.warn(error.details[0].message); } }
注意:如果之前替换
throw为info没生效,检查以下几点:
info方法是否正确引入(比如是否是日志服务的实例,有没有在类中注入)- 日志级别是否配置正确(比如
info级别的日志是否被输出到控制台/文件)- 错误信息是否被正确获取(比如
error.details是否为空,或者需要遍历所有错误)
步骤2:确保处理器流程正常执行
修改后的validate方法不再抛出错误,因此处理器中的command.validate()执行后,会直接继续执行后续的repository.register(dto)逻辑,无需额外修改处理器代码。
验证效果
当传入无效负载时,控制台/日志系统会输出验证错误的警告信息,同时事件会正常存入数据库,不会被中断。
内容的提问来源于stack exchange,提问作者Nickie Ferrante
相关产品推荐
相关产品推荐

