` 验证链的全部能力)
后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载导读Validation Chain验证链是 express-validator 的核心抽象通过check()、body()、query()等入口创建的链式对象把 validator.js 的几十个标准校验器、express-validator 独有的自定义校验器与链操作符not()、optional()、withMessage()统一串成一段可复用的 Express 中间件。本文基于仓库内 version-5.3.0 版本文档结合当前仓库源码逐方法拆解验证链的 API 语义、调用约定与底层实现帮助你写出可读、可复用、行为可预期的路由校验代码。一、验证链是什么从check()到链式调用在 express-validator 5.x 中一切从require(express-validator/check)导出的 check API 开始const { check } require(express-validator/check); app.post(/create-user, [ check(password).exists().isLength({ min: 8 }).withMessage(密码至少 8 位), ], loginHandler);check(password)返回一个Validation Chain。它本质上是一个具备双重身份的对象它是中间件可以直接放进 Express 路由的app.use()/ 路由数组中使用它可链式调用ValidationChain接口同时继承了Validators、Sanitizers、ContextHandler与ContextRunner的能力见 src/chain/validation-chain.ts。其中ValidatorsValidationChain定义了全部校验器方法的签名见 src/chain/validators.ts每一个方法都返回Return即链本身因此可以无限追加调用。二、两条铁律链是可变的、净化先于校验原文档在开头就强调两个容易踩坑的语义理解它们比记住任何单个方法都重要1. 链是可变的mutable。每次调用链上的方法都是在同一个链对象上追加行为而不是返回一个新链。这意味着如果你把一个链实例复用到多条路由上前面累积的校验器会全部保留并叠加因此当你想“复用某个链的基础部分”时应当使用工厂函数每次返回新链而不是缓存链实例// 错误示范base 被第一条路由用过后第二条路由会继续累积校验器 const base check(email).isEmail(); app.post(/a, [base, /* ... */]); app.post(/b, [base, /* ... */]); // base 上已挂上 /a 追加的校验器 // 正确示范工厂函数每次生成全新链 const baseChain () check(email).isEmail(); app.post(/a, [baseChain()]); app.post(/b, [baseChain()]);2. 净化sanitization先于校验validation。验证链上可以同时挂净化器和校验器。如果一个字段先经过trim()之类的净化器再被校验那么被校验的值是净化后的值。这也解释了为什么SanitizersValidationChain会被并进ValidationChain接口src/chain/validation-chain.ts净化器和校验器在同一链上按书写顺序依次对字段值生效。三、validator.js 全量方法开箱即用的校验器库所有由 validator.js 提供的校验与净化方法只要 express-validator 支持到的最新 validator 版本中存在就会全部暴露到每一条验证链上。你不需要单独引入 validator.jscheck(email).isEmail(); check(ip).isIP(); // IPv4/IPv6 check(url).isURL(); check(uuid).isUUID(4); check(age).isInt({ min: 18, max: 99 }); check(name).isLength({ min: 2, max: 20 }); check(phone).isMobilePhone(zh-CN); check(code).matches(/^[A-Z]{3}\d{3}$/);从当前仓库源码可以确认这一机制的实现方式ValidatorsImpl通过addStandardValidation()把每个标准校验器包装成StandardValidation上下文项src/chain/validators-impl.ts并且测试用例遍历 validator 模块中所有以is开头的方法逐一断言它们都出现在验证链上。仓库当前源码还额外提供了isObject()、notEmpty()、isStrongPassword()、isLuhnNumber()、isTaxID()等更丰富的成员src/chain/validators.ts可直接在链上使用。四、验证链核心方法逐一详解除了 validator.js 的标准方法验证链还额外提供以下 8 个方法它们是 express-validator 自己实现的控制能力。4.1.custom(validator)— 自定义校验器签名custom(validator)其中validator(value, { req, location, path })返回当前验证链。为当前验证链追加一个自定义校验函数。它收到value正在被校验的字段值{ req, location, path }Express 请求对象、字段所在位置body/query/params/headers/cookies、字段路径。判定规则返回falsy 值→ 字段无效抛出自定义异常如throw new Error(...)→ 字段无效且异常信息会成为错误消息返回Promise→ 视为异步校验Promise被拒绝rejected→ 字段无效。官方示例校验两次输入的密码一致app.post(/create-user, [ check(password).exists(), check(passwordConfirmation, passwordConfirmation field must have the same value as the password field) .exists() .custom((value, { req }) value req.body.password) ], loginHandler);结合源码看.custom()在内部创建CustomValidation上下文项并压入 ContextBuilder 的栈中src/chain/validators-impl.ts。CustomValidation.run()的实现src/context-items/custom-validation.ts精确定义了上述判定逻辑对返回值取反判断失败对异步结果await后判断catch分支里如果自定义校验器抛出的不是Error实例例如Promise.reject(字符串)错误消息会直接使用被抛出的原始值。4.2.customSanitizer(sanitizer)— 自定义净化器与净化链上的.customSanitizerSanitization Chain API 行为完全一致。它的作用是在验证链上直接追加一个自定义净化函数通常用于“先转换字段值、再让后续校验器作用于转换后的值”的场景。净化器同样收到(value, { req, location, path })且必须同步返回新值。check(id).customSanitizer((value, { req }) { return req.query.type user ? ObjectId(value) : Number(value); }).isMongoId();结合净化链文档中的示例可以看到完整用法净化发生在校验之前因此同一个链上先customSanitizer转换、再校验是常见且有效的组合。链上可用的其他净化方法trim、toInt、toBoolean、escape、blacklist、whitelist、normalizeEmail等定义在 src/chain/sanitizers.ts。4.3.exists(options)— 字段存在性校验签名exists(options?)options为可选对象返回当前验证链。校验当前字段在请求中存在。默认语义字段值不能是undefined其余任何值包括null、0、、false都算存在。可通过options收紧语义选项类型默认值行为checkNullbooleanfalse为true时值为null的字段视为“不存在”checkFalsybooleanfalse为true时一切 falsy 值、0、false、null等都视为“不存在”// 默认只有 undefined 会失败 check(name).exists(); // null 也被判为不存在 check(nickname).exists({ checkNull: true }); // 、0、false、null、undefined 全部判为不存在 check(agree).exists({ checkFalsy: true });底层实现把.exists()直接包装成一个自定义校验器checkFalsy时用value !!valuecheckNull时用value value ! null默认用value value ! undefinedsrc/chain/validators-impl.ts。validators-impl.spec.ts 的测试也精确验证了这三种模式下对undefined / null / 0 / / false / true的判定结果。4.4.isArray()— 数组校验返回当前验证链。校验字段值是一个数组。结合当前仓库源码它还支持{ min, max }选项限定数组长度范围src/chain/validators.ts实现上等价于Array.isArray(value)且长度满足min/max约束src/chain/validators-impl.tscheck(tags).isArray({ min: 1, max: 10 });4.5.isString()— 字符串校验返回当前验证链。校验字段值是字符串。实现等价于typeof value stringsrc/chain/validators-impl.tscheck(username).isString();4.6.not()— 取反下一个校验器返回当前验证链。对紧邻的下一个校验器结果取反。官方示例check(weekday).not().isIn([sunday, saturday]) // 等价语义weekday 不能是 sunday 或 saturday注意.not()只影响紧随其后的一个校验器不会影响后面的其他校验器这是它的实现保证的not()只把negateNext标记置为true而addItem()在添加完当前校验项后会立刻重置该标记src/chain/validators-impl.ts。notEmpty()也正是通过先调用this.not()再执行isEmpty()组合出来的src/chain/validators-impl.ts。4.7.optional(options)— 标记字段为可选签名optional(options?)options为可选对象返回当前验证链。把当前验证链标记为可选当字段未在请求中提供时跳过校验。这是业务中最常用的方法之一——用于“非必需字段缺省时不报错”的场景。默认语义值为undefined的字段会被忽略不参与任何校验。可通过options扩展可选范围选项类型默认值行为nullablebooleanfalse为true时值为null的字段也视为可选checkFalsybooleanfalse为true时一切 falsy 值、0、false、null都视为可选// 默认undefined 时忽略null 仍会触发校验 check(bio).optional().isLength({ max: 200 }); // null 时也忽略 check(avatar).optional({ nullable: true }).isURL(); // 空字符串、0、false、null 都忽略 check(remark).optional({ checkFalsy: true }).isString();结合净化链Sanitization Chain的用法可以组成常见模式先用default()之类的净化器兜底再用optional({ checkFalsy: true })统一处理空值避免空值触发误报。实现上optional()最终调用ContextBuilder.setOptional()把可选策略写入上下文src/chain/context-handler-impl.ts。当前仓库源码还提供了更细粒度的values: undefined | null | falsy选项src/chain/context-handler.ts并标记nullable/checkFalsy为已弃用——这说明该能力在后续版本中语义统一、能力只增不减。4.8.withMessage(message)— 为上一条校验设置错误消息签名withMessage(message)message为错误消息返回当前验证链。为前一条校验器设置错误消息。关键语义优先级最高它覆盖自定义校验器抛出的错误消息按校验器粒度生效链上多个校验器各自携带自己的消息互不干扰。check(password) .isLength({ min: 5 }).withMessage(密码至少 5 个字符) .matches(/\d/).withMessage(密码必须包含数字);实现机制withMessage()直接改写lastValidator.messagesrc/chain/validators-impl.ts其中lastValidator是上一次addItem()记录的上一个校验项。这也解释了“它只作用于前一个校验器”的语义来源。消息还支持动态生成message可以是一个函数(value, { req, location, path }) string非常适合接入 i18n 翻译库详见错误消息专题Dynamic Messages。错误消息的三级体系校验器级 / 自定义校验器级 / 字段级也在该文档中完整阐述字段级消息由check(field, message)的第二个参数提供check API。五、底层原理验证链是如何“跑起来”的从源码结构看验证链的工作机制可以归纳为三个层次1. 构建期build每次链式调用如.exists()、.custom()、.bail()、.optional()都会往ContextBuilder内部的stack数组追加一个上下文项src/context-builder.ts。最终build()产出包含字段、位置、可选策略、错误消息与校验项栈的Contextsrc/context-builder.ts。2. 运行期run验证链作为中间件执行时ContextRunner会按顺序依次运行栈中每个ContextItem校验器 / 净化器 / 条件项对请求指定位置的字段值逐个生效。3. 错误收集校验失败时错误被写入Context.errors最终通过validationResult(req)提取为Validation Result 对象供路由处理。由此可以推断出两条实用结论同一字段的校验器串行执行链上的校验器按书写顺序依次运行见 check API 中“validators 对同一字段串行执行”的说明复用链必须用工厂函数由于链可变、校验项持续累积一旦把链实例在多个路由间共享后注册的校验器会污染先注册路由的校验逻辑。六、进阶衔接验证链的完整生态验证链并非孤立存在它在 express-validator 中与其他 API 紧密配合创建入口check()、body()、cookie()、header()、param()、query()、buildCheckFunction(locations)都返回验证链check API批量校验checkSchema(schema)根据 schema 定义生成一组验证链Schema Validation组合校验oneOf([...])要求至少一组链通过支持嵌套数组表示“组内全部通过”check API 中的 oneOf 示例错误处理validationResult(req).throw()或手动遍历结果对象Validation Result API自定义校验/净化更多写法与最佳实践参见 Custom Validators Sanitizers。七、小结与最佳实践验证链是可变对象复用基础链务必用工厂函数净化先于校验customSanitizer/trim等转换结果会直接进入后续校验器validator.js 全量方法开箱即用无需重复引入依赖直接用isEmail、isInt、matches等.not()只作用于下一个校验器利用它实现“不在这组值里”的语义.optional()是处理非必需字段的默认首选按需启用nullable/checkFalsy.withMessage()按校验器粒度定制错误消息并支持动态消息函数配合错误消息专题可建立完整的多级错误文案体系。对于阅读源码的开发者可从 src/chain/validation-chain.ts、src/chain/validators-impl.ts 与 src/chain/validators-impl.spec.ts 三个文件入手完整追踪“链式调用 → 上下文项入栈 → 中间件执行 → 错误收集”的完整链路从而对验证链的每个 API 语义建立源码级的确信。赞分享后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载相关推荐通达信ChanlunX缠论插件3分钟实现自动化缠论分析告别手工画线通达信ChanlunX缠论插件3分钟实现自动化缠论分析告别手工画线 缠论作为中国本土的技术分析理论以其严谨的数学逻辑和独特的市场视角赢得了众多投资者的青睐。金融科技AMD显卡AI创作的终极解决方案ComfyUI-Zluda深度解析与实践指南AMD显卡AI创作的终极解决方案ComfyUI Zluda深度解析与实践指南 还在为AMD显卡无法充分发挥AI创作潜力而困扰吗ComfyUI Zluda正是人工智能大模型媒体生成计算机视觉后端AI工程革命从提示词模板到智能体生态的开发者生产力跃迁AI工程革命从提示词模板到智能体生态的开发者生产力跃迁 2026年的AI开发格局正在经历一场深刻的范式转移——从写提示词到设计智能体系统的工程化演进。提示工程文档人工智能上一篇AngularFire Realtime Database 列表数据实战指南AngularFireList 的读取、写入与删除全解析下一篇Windows 视频缩略图不显示3步修复完整排障指南MPC-BE 用户必看创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考