完整实战指南:对象式声明校验与净化规则)
后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载本指南围绕 express-validator 5.3.0 版本中提供的checkSchema()特性展开讲解如何以纯对象Schema的方式声明式地描述请求字段的位置、错误消息、验证器与净化器并深入其底层源码实现与测试用例。读完本文你将掌握 Schema 校验的全部语法要素in、errorMessage、optional、options、negated、bail、if、custom、customSanitizer与通配符路径并能在实际 Express 路由中直接落地使用。Schema 校验是什么在 express-validator 中除了用函数式 API如check(email).isEmail()逐条拼接验证链之外还提供了一种对象式、声明式的定义方式——Schema 校验。官方文档feature-schema-validation.md将其概括为Schemas are a special, object-based way of defining validations or sanitizations on requests.也就是说Schema 是一种特殊的、基于对象的方式来定义请求上的校验与净化操作。其基本结构是根级键root-level keys指定字段路径field paths键对应的对象值定义该字段的错误消息、校验位置locations以及验证/净化规则。从源码结构看Schema 校验并不是一套独立的机制checkSchema返回的实际上是一组校验链ValidationChain数组。在 src/middlewares/schema.ts 中createCheckSchema()会将 schema 中的每个字段逐条转换为一个校验链这与文档所述“schema 只是校验链的另一种写法”完全一致。当前版本docs中的指南也明确说明They offer exactly the same functionality as regular validation chains - in fact, under the hood, express-validator deals all in validation chains!因此只要理解了校验链的语义就能完全掌握 Schema 校验。导入方式与基本用法在 5.3.0 中checkSchema从express-validator/check子模块导出const { checkSchema } require(express-validator/check);它接收一个 schema 对象返回校验链数组array of validation chains可直接作为 Express 路由中间件使用。官方示例feature-schema-validation.mdconst { checkSchema } require(express-validator/check); app.put(/user/:id/password, checkSchema({ id: { // 字段位置可以是 body、cookies、headers、params、query 中的一个或多个 // 如果省略将检查所有请求位置 in: [params, query], errorMessage: ID is wrong, isInt: true, // 净化器同样可以写在这里 toInt: true }, password: { isLength: { errorMessage: Password should be at least 7 chars long, // 多个选项以数组形式表达 options: { min: 7 } } }, firstName: { isUppercase: { // 取反一个验证器 negated: true, }, rtrim: { // 选项以数组形式给出 options: [ -], }, }, // 通配符 / 点号同样适用于嵌套字段 addresses.*.postalCode: { optional: true, isPostalCode: true } }), (req, res, next) { // 照常处理请求 });上面的示例已经覆盖了 Schema 校验的核心要素字段位置in、通用错误消息errorMessage、验证器isInt、isLength、isUppercase、isPostalCode、净化器toInt、rtrim、选项options、取反negated、可选字段optional以及通配符路径。下文逐一展开。Schema 的语法结构与核心概念字段路径作为键Schema 是一个普通 JavaScript 对象键是字段路径值是该字段的校验规则对象。字段路径的解析沿用与check()相同的字段选择规则可参考 docs/guides/field-selection.md。在 JS 中通配符*不能直接作为对象键因此必须用引号包裹checkSchema({ addresses.*.street: { notEmpty: true, }, addresses.*.number: { isInt: true, }, });字段规则对象的组成一个字段的规则对象field schema / ParamSchema由四类键混合组成源码类型定义见 src/middlewares/schema.ts内置验证器built-in validators如isInt、isLength、isEmail内置净化器built-in sanitizers如toInt、trim、escape、rtrim字段修饰符field modifiersin、errorMessage、optional自定义键名custom schema值中包含custom或customSanitizer函数表示自定义验证器/净化器。源码中的protectedNames [errorMessage, in, optional]src/middlewares/schema.ts明确声明了这三个修饰符名称在遍历字段键时会被跳过不会当作验证器/净化器处理。字段修饰符in / errorMessage / optionalin指定字段校验的请求位置可以是body、cookies、headers、params、query中的单个字符串或数组。省略时默认检查所有请求位置源码中默认值即validLocations数组见 src/middlewares/schema.ts。errorMessage字段级通用错误消息在该字段任一验证器未通过且验证器自身没有指定errorMessage时使用。从源码看这个值在创建校验链时作为check(field, locations, errorMessage)的第三个参数传入src/middlewares/schema.ts等价于check(password, 错误消息)。optional将字段标记为可选。可以设为true也可以设为带options的对象来细化可选判定如checkFalsy、nullable。源码中对应调用校验链的.optional()方法if (config.optional) { chain.optional(config.optional true ? true : config.optional.options); }对应的测试用例src/middlewares/schema.spec.ts验证了两种写法的效果optional: true产生undefined可选判定optional: { options: { checkFalsy: true, nullable: true } }产生falsy可选判定。配置内置验证器Validators简写设置为 true内置验证器直接设为true表示启用且不传任何选项checkSchema({ email: { isEmail: true }, password: { notEmpty: true }, });这等价于check(email).isEmail(); check(password).notEmpty();options传参的两种形态验证器的值也可以是对象此时通过options字段传入参数。如果验证器需要多个参数options必须是一个数组只有一个参数时可以直接传值checkSchema({ phone: { isMobilePhone: { options: [any, { strictMode: true }], // 等价于 isMobilePhone(any, { strictMode: true }) }, }, password: { isLength: { options: { min: 8 }, // 等价于 isLength({ min: 8 }) }, }, });需要注意一个易错点如果某个验证器的唯一参数本身就是数组例如isIn该数组必须再被包裹一层否则会被展开成多个参数checkSchema({ weekend: { // 错误写法会被翻译成 isIn(saturday, sunday) isIn: { options: [saturday, sunday] }, // 正确写法翻译成 isIn([saturday, sunday]) isIn: { options: [[saturday, sunday]] }, }, });这与源码中_.castArray(entry[1].options)的展开逻辑src/middlewares/schema.ts相对应options 会被强制转换为数组后以展开spread方式传给验证器。negated取反验证器对验证器取反等价于校验链上的.not()。例如“密码不能为空”checkSchema({ password: { isEmpty: { negated: true }, }, });源码中取反操作发生在验证器之前validatorConfig.negated chain.not()src/middlewares/schema.ts测试用例src/middlewares/schema.spec.ts验证了对isEmpty取反后空字符串会触发错误。bail验证失败即中断在验证器配置中加入bail: true若当前验证器或之前的验证器失败则后续验证器不再运行等价于.bail()checkSchema({ email: { // 先运行 isEmail如果邮箱不合法后面的 custom 验证器不会执行 isEmail: { bail: true }, custom: { options: checkEmailNotInUse }, }, });源码中bail调用被放在验证器之后validatorConfig.bail chain.bail(...)见 src/middlewares/schema.ts并且支持配置对象形式如{ level: request }。src/middlewares/schema.spec.ts 中的测试覆盖了单字段 bail、校验通过不中断、带错误消息 bail、多个 bail 叠加以及请求级 baillevel: request时后续字段的校验链不再运行等场景。if条件式执行通过if为验证器设置前置条件条件不满足则该验证器及其后的验证器都不运行。if既可以是自定义验证函数也可以是另一个校验链如body(oldPassword).notEmpty()checkSchema({ newPassword: { exists: { // 使用自定义验证函数作为条件 if: (value, { req }) !!req.body.oldPassword, // 或使用校验链作为条件 if: body(oldPassword).notEmpty(), }, }, });源码中validatorConfig.if chain.if(validatorConfig.if)被放在验证器执行之前src/middlewares/schema.ts测试用例src/middlewares/schema.spec.ts验证了if条件为 false 时验证链停止执行、不产生错误。errorMessage验证器级错误消息在每个验证器内部设置errorMessage只影响该验证器失败时的错误文本等价于.withMessage()checkSchema({ email: { isEmail: { errorMessage: Must be a valid e-mail address, }, }, });它和字段级errorMessage的优先级关系是验证器自身的errorMessage优先。源码中验证器配置里的errorMessage会通过chain.withMessage(...)追加在验证器之后src/middlewares/schema.ts。测试用例src/middlewares/schema.spec.ts进一步确认只有验证器会接受errorMessage净化器sanitizer和optional中的errorMessage不会被错误地设置到校验栈上。配置内置净化器Sanitizers净化器的配置方式与验证器完全对称可以设为true表示无参数调用也可以用对象配合options传参checkSchema({ query: { trim: true }, // 等价于 check(query).trim() email: { normalizeEmail: { options: { gmail_remove_subaddress: true }, // 等价于 normalizeEmail({ gmail_remove_subaddress: true }) }, }, });多参数时同样要求options为数组。净化器选项SanitizerSchemaOptions只支持options字段见 src/middlewares/schema.ts这一点与验证器不同——验证器配置还支持negated、bail、if、errorMessage等行为修饰。自定义验证器与自定义净化器方式一custom / customSanitizer 键在字段 schema 中直接写custom或customSanitizer行为与普通验证器/净化器一致也支持options等配置checkSchema({ email: { custom: { options: checkIfEmailExists, // 自定义验证器 bail: true, }, customSanitizer: { options: removeEmailAttribute, // 自定义净化器 }, }, });等价于check(email).custom(checkIfEmailExists).bail().customSanitizer(removeEmailAttribute);自定义验证器函数签名是(value, { req, location, path })官方示例feature-schema-validation.md展示了自定义验证器与净化器同时出现的完整写法myCustomField: { // 自定义验证器 custom: { options: (value, { req, location, path }) { return value req.body.foo location path; } }, // 自定义净化器 customSanitizer: { options: (value, { req, location, path }) { let sanitizedValue; if (req.body.foo location path) { sanitizedValue parseInt(value); } else { sanitizedValue 0; } return sanitizedValue; } }, }关于自定义验证器/净化器的更多进阶用法如 Promise 异步校验、通过throw/reject自定义错误消息可参考 feature-custom-validators-sanitizers.md。方式二任意命名键 custom / customSanitizer 函数custom/customSanitizer写法有一个限制每个字段只能设置一个自定义验证器和一个自定义净化器因为 JS 对象中同名字段只保留最后一个值。为了支持多个自定义验证器/净化器可以给字段 schema 设置一个不属于任何内置验证器、净化器或修饰符的自定义键名其值为包含单个custom或customSanitizer函数的对象checkSchema({ email: { emailNotInUse: { custom: checkEmailNotInUse, bail: true, }, removeEmailAttribute: { customSanitizer: removeEmailAttribute, }, }, });这里emailNotInUse、removeEmailAttribute只是占位键名checkSchema()不会使用这些名字不同的 schema 可以复用同一个名字而不会冲突。源码中通过四个类型守卫函数isStandardValidator、isStandardSanitizer、isCustomValidator、isCustomSanitizer见 src/middlewares/schema.ts判断键的类型当键既不是内置验证器也不是内置净化器、且值对象中含有custom/customSanitizer函数时才被识别为自定义校验/净化入口。测试用例src/middlewares/schema.spec.ts验证了随机命名的自定义验证器与净化器会被正确调用、以及在内置验证器/净化器名下挂custom不会被误执行。通配符与嵌套字段Schema 键支持与字段选择一致的通配符*与嵌套点号路径例如一次校验数组中所有元素的postalCodecheckSchema({ addresses.*.postalCode: { optional: true, isPostalCode: true, }, });在 JavaScript 中*必须用引号包裹才能作为对象键。通配符的高级特性globstar 等与check()的字段选择能力一致可参考 docs/guides/field-selection.md 中的 Advanced Features 部分。源码视角checkSchema 是如何工作的checkSchema本质上是createCheckSchema(check)的工厂产物src/middlewares/schema.ts其工作流程如下遍历 schema 的每个字段Object.keys(schema).map(...)为每个字段调用check(field, locations, errorMessage)创建一条校验链src/middlewares/schema.ts。check本身由ContextBuilder与ContextRunnerImpl组装而成src/middlewares/check.ts。处理optional无论字段中的其他键顺序如何optional总是先被处理。遍历字段规则对象的每个键跳过errorMessage、in、optional三个保护名以及所有值为假!entry[1]的条目对未知键名输出警告express-validator: schema of ... has unknown validator/sanitizer ...并跳过src/middlewares/schema.ts。按序组装校验链对验证器先追加if、negatednot()再追加验证器本身最后追加bail与errorMessagewithMessage()对净化器直接追加调用对自定义验证器/净化器追加custom()/customSanitizer()src/middlewares/schema.ts。位置归一化ensureLocations()将in字符串或数组归一化为合法位置数组过滤掉非法值未指定in时使用defaultLocations默认全部五个位置见 src/middlewares/schema.ts。测试文件 src/middlewares/schema.spec.ts 对以上行为给出了系统性的验证每个字段生成一条链creates a validation chain for each field in the schema、默认校验全部位置、in支持字符串与数组、未知验证器触发警告且不进入校验栈、禁用false的验证器既不警告也不生效、not/withMessage不允许出现在 schema 中、falsy 值如options: 0能正确传给方法见correctly pass falsy values to options用例等。进阶手动运行与默认位置checkSchema()返回的校验链数组同时实现了ContextRunner接口因此除了作为 Express 中间件使用外也可以手动调用.run(req)获得校验结果app.post(/signup, async (req, res) { const results await checkSchema({ email: { isEmail: true }, password: { isLength: { options: { min: 8 } } }, }).run(req); const hasErrors results.some(result !result.isEmpty()); if (hasErrors) { const errors results.flatMap(result result.array()); return res.status(400).json({ errors }); } });源码中run通过runAllChains(req, chains)并行执行全部校验链并返回结果数组src/middlewares/schema.ts对应测试run checkSchema imperativelysrc/middlewares/schema.spec.ts。另外checkSchema还接受第二个参数defaultLocations用于修改字段未指定in时的默认校验位置checkSchema(schema, [body, query]);此时所有未写in的字段默认只校验body和query而单个字段的in优先级更高会覆盖defaultLocations。测试用例src/middlewares/schema.spec.ts覆盖了默认全位置、自定义默认位置、in为字符串与数组四种情形。小结Schema 校验checkSchema()是 express-validator 提供的声明式校验方案与函数式校验链功能完全等价、底层共用同一套校验链实现。它通过“字段路径作键、规则对象作值”的结构集中管理字段位置in、错误消息errorMessage/errorMessage、可选标记optional以及全部内置/自定义验证器与净化器并借助options、negated、bail、if等修饰符实现细粒度的行为控制还能通过通配符路径覆盖嵌套字段。对于偏好“配置式”而非“代码式”描述接口校验规则的开发者Schema 校验是 express-validator 中最合适的选择。其完整类型定义与 API 细节可进一步查阅 docs/api/check-schema.md 与 docs/guides/schema-validation.md。赞分享后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载相关推荐express-validator 的 Schema 校验用 checkSchema 声明式定义请求校验与净化规则express validator 的 Schema 校验用 checkSchema 声明式定义请求校验与净化规则 导读 express validator后端express-validator 声明式校验checkSchema 与 Schema Validation 完整实战指南express validator 声明式校验checkSchema 与 Schema Validation 完整实战指南 导读 本文聚焦 express v后端express-validator Schema Validation 完整指南用 checkSchema() 以声明式对象定义请求校验与净化express validator Schema Validation 完整指南用 checkSchema 以声明式对象定义请求校验与净化 导读 本文聚焦 e后端上一篇【亲测免费】 FastT5: 加速T5模型推理的神器下一篇Vehicle-Security-Toolkit 使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考