基于JOI实现依赖其他字段的自定义表单验证求助
Joi实现依赖多字段的自定义验证规则
问题分析
你之前的尝试存在两个核心问题:
when示例只单独判断了email的空值,没结合mobile的状态,无法覆盖“email和mobile均为空”的场景or示例仅检查字段是否存在且通过验证,但如果字段存在但值为空(比如email: ''),Joi会认为该字段验证通过,导致or逻辑不符合你“值不能为空”的实际需求
解决方案
以下是精准匹配需求的验证代码,同时实现**“email和mobile均空时username必填”和“username空时email/mobile至少一个有有效值”**的双向约束:
const joi = require('joi'); const validations = joi.object({ username: joi.string() // 正向约束:当email和mobile都为空值时,username必填 .when(joi.object({ email: joi.valid('', null, undefined), mobile: joi.valid('', null, undefined) }), { is: joi.object().required(), then: joi.required().messages({ 'any.required': '当email和mobile均为空时,username为必填项' }), otherwise: joi.optional() }), // 定义email的实际验证规则,允许空值但可选 email: joi.string().email().optional().allow('', null, undefined), // 定义mobile的实际验证规则(示例为国内手机号正则),允许空值但可选 mobile: joi.string().pattern(/^1[3-9]\d{9}$/).optional().allow('', null, undefined) }) // 反向约束:username为空时,email或mobile至少一个不为空 .or( joi.object({ username: joi.invalid('', null, undefined) }).unknown(), joi.object({ email: joi.invalid('', null, undefined) }).unknown(), joi.object({ mobile: joi.invalid('', null, undefined) }).unknown() ) .options({ abortEarly: false });
关键逻辑说明
正向约束:
- 通过
joi.object()作为when的条件,同时校验email和mobile是否都为空值(包含空字符串、null、undefined) - 满足条件时强制
username必填,否则保持可选
- 通过
反向约束:
- 用
.or()组合三个条件:要么username有有效值,要么email有有效值,要么mobile有有效值 .unknown()确保其他字段不会干扰当前约束的判断
- 用
字段类型优化:
- 替换
joi.any()为对应字段的实际验证规则(比如邮箱格式、手机号正则),既提升验证精准度,也避免空值被误判为有效字段
- 替换
测试验证
- ✅ email和mobile均为空 → 必须填username,否则报错
- ✅ username为空 → email或mobile至少一个填有效值,否则报错
- ✅ username有值 → email和mobile可全空,验证通过
- ✅ email/mobile有有效值 → username可空,验证通过
内容的提问来源于stack exchange,提问作者Mr.Singh
相关产品推荐
相关产品推荐

