express-validator 校验中间件完全指南:check、body、checkSchema、oneOf 与 buildCheckFunction 深入解析
后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载express-validator 是一套运行在 Express 之上的请求校验与净化中间件其所有校验入口都通过require(express-validator)暴露。本文围绕 v6.3.0 文档 api-check.md 中定义的五组核心 APIcheck、body/cookie/header/param/query、checkSchema、oneOf、buildCheckFunction展开结合仓库源码如 validation-chain-builders.ts、check.ts、one-of.ts、schema.ts讲解它们各自的用途、执行语义与底层实现帮助读者在实际 Express 路由中正确选用合适的校验入口。总览express-validator 的校验中间件家族在 express-validator 中校验中间件validation middleware指那些负责从请求对象中取出字段、运行校验规则、并把错误记录到请求上下文context中的函数。它们全部从包的主入口导出见 index.tsconst { check, body, cookie, header, param, query, checkSchema, oneOf, buildCheckFunction } require(express-validator);这些 API 可分为三类按字段选择类check、body、cookie、header、param、query返回一个 校验链Validation Chain按 Schema 批量定义类checkSchema返回一组校验链组成的数组多组候选项类oneOf返回一个可整体判断至少一组通过的中间件实例。check([field, message])通用的字段校验入口check()是 express-validator 最核心的校验入口。它接受两个可选参数field(可选)一个字符串或字符串数组表示要校验的字段名message(可选)当校验器validator没有指定自定义消息时使用的兜底错误消息默认值为Invalid value。关于动态消息即把消息写成函数的形式见 自定义错误消息指南。返回值一个 校验链Validation Chain。check()创建的校验链会在以下任一请求对象中查找字段req.bodyreq.cookiesreq.headersreq.paramsreq.query跨位置重复校验语义如果某个字段同时出现在多个位置那么该字段在所有出现位置的值都必须通过校验。例如check(id).isInt()会同时校验req.body.id、req.query.id、req.params.id等所有已解析出的id只要其中任何一个不是整数就会报错。省略字段Whole Body Validation如果省略field则校验整个请求位置。这个用法对req.body尤其有意义——当请求体本身就是字符串、数组或数字而非对象时例如Content-Type: text/plain的请求可用body().isEmail()直接校验整个请求体具体示例见 Whole Body Validation。串行与并行的执行语义校验器对同一个字段总是串行执行如果校验链同时针对多个字段则不同字段之间的校验并行运行但每个字段各自的校验器保持串行。这一语义在oneOf中同样被继承详见下文。源码实现check 如何构建一条校验链在 check.ts 中可以看到check的实现骨架export function check( fields: string | string[] , locations: Location[] [], message?: FieldMessageFactory | ErrorMessage, ): ValidationChain { const builder new ContextBuilder() .setFields(Array.isArray(fields) ? fields : [fields]) .setLocations(locations) .setMessage(message); const runner new ContextRunnerImpl(builder); // ...返回一个被 bindAll 扩展过的 Express 中间件 }关键点fields被统一归一化为数组Array.isArray(fields) ? fields : [fields]交给ContextBuilder管理message的类型可以是普通值ErrorMessage即 string/number/symbol/boolean/object/array或一个消息工厂函数FieldMessageFactory接收字段值与Meta元数据返回消息见 base.ts 中的类型定义返回的对象是中间件 校验链的混合体它本身是可被 Express 直接app.use的(req, res, next)异步中间件同时通过Object.assign合并了ContextRunnerImpl、SanitizersImpl、ValidatorsImpl、ContextHandlerImpl实例上所有绑定方法如.isInt()、.custom()、.withMessage()、.bail()等因此可以链式调用。位置限定变体body / cookie / header / param / query这五个函数与check([fields, message])行为完全一致只是把字段查找范围限定在单一请求位置函数校验的请求对象body([fields, message])仅req.bodycookie([fields, message])仅req.cookiesheader([fields, message])仅req.headersparam([fields, message])仅req.paramsquery([fields, message])仅req.query例如const { body, query, param } require(express-validator); app.post(/user, [ body(email).isEmail(), // 只校验 req.body.email body(password).isLength({ min: 6 }), query(page).optional().isInt(), // 只校验 req.query.page param(userId).isUUID(), // 只校验 req.params.userId ], handler);源码实现在 validation-chain-builders.ts 中这些变体都是通过buildCheckFunction生成的——每个变体本质上就是check(fields, locations, message)的一个预置了locations的偏函数export const check buildCheckFunction([body, cookies, headers, params, query]); export const body buildCheckFunction([body]); export const cookie buildCheckFunction([cookies]); export const header buildCheckFunction([headers]); export const param buildCheckFunction([params]); export const query buildCheckFunction([query]);可以看到check本身也不是特殊实现而是五个位置全选的buildCheckFunction结果这解释了为何check会在所有位置同时校验同名字段。checkSchema(schema)用对象声明式批量定义校验checkSchema接受一个 schema 对象按 Schema Validation 指南 中描述的格式定义多个字段的校验与净化规则返回一个由校验链组成的数组可整体直接作为中间件使用也可整体调用.run(req)手动运行。schema待校验的 schema必须符合 Schema Validation 中描述的格式。返回值一组校验链ValidationChain[]。典型用法const { checkSchema } require(express-validator); app.put(/user/:id/password, checkSchema({ id: { // 字段位置可为 body / cookies / headers / params / query 中的任意多个 // 省略时默认在所有请求位置查找 in: [params, query], errorMessage: ID is wrong, isInt: true, toInt: true // 净化器sanitizer同样可以写在 schema 中 }, password: { isLength: { errorMessage: Password should be at least 7 chars long, options: { min: 7 } // 多个参数以数组形式表达如 options: [7, 10] } }, firstName: { isUppercase: { negated: true }, // negated 取反校验 rtrim: { options: [ -] } }, // 通配符 / 点号嵌套字段同样支持 addresses.*.postalCode: { optional: { options: { nullable: true } }, // 字段为 undefined 或 null 时可选 isPostalCode: true } }), (req, res, next) { // 正常处理请求 });schema 中每个字段可配置的属性包括in位置、errorMessage兜底消息、optional可选字段、所有内置校验器/净化器如isInt、isLength、isUppercase、toInt、rtrim值可为true、选项对象或带options的对象以及custom/customSanitizer自定义校验器/净化器。每个校验器条目还支持negated取反、bail失败后短路、if条件执行、errorMessage本条消息等扩展选项。源码实现schema 如何被编译为校验链在 schema.ts 中checkSchema由createCheckSchema(check)工厂函数生成。编译过程的核心逻辑如下顶层Schema类型是Recordstring, ParamSchema即字段名 → 配置对象的映射见src/middlewares/schema.ts中的类型定义每个字段配置里in决定 locations未设置时默认使用全部合法位置[body, cookies, headers, params, query]即validLocations常量protectedNames [errorMessage, in, optional]是保留字不会当作校验器处理校验器条目会被翻译成链上的chain.if(...)→chain.not()若 negated→chainvalidator→chain.bail(...)→chain.withMessage(...)这样的调用序列保证if/negated位于校验器之前、bail/withMessage位于之后校验器值传true时表示无选项调用传对象时其options会被_.castArray归一化为参数数组无法识别的键会通过console.warn输出express-validator: schema of field has unknown validator/sanitizer name警告并跳过最终返回的数组额外挂载了一个run(req)方法RunnableValidationChains可编程式运行全部链。oneOf(validationChains[, message])至少一组通过oneOf用于表达多选一的校验逻辑只要给定校验链中至少一条通过请求即视为通过校验。validationChains由check()及其变体创建的校验链组成的数组数组元素也可以是校验链的数组即一组链组内必须全部通过才视为该组有效message(可选)所有链都失败时使用的错误消息默认值为Invalid value(s)同样支持动态消息动态消息函数只接收{ req }返回值一个中间件实例。失败时的错误结构如果所有给定链都未通过oneOf会向请求的_error伪字段推入一个错误消息使用给定的message并且每条链产生的错误会集中存放在该错误的nestedErrors键下。在 v6.3.0 中该错误对应 base.ts 中定义的AlternativeValidationErrortype: alternative类型。示例——用户必须掌握编程语言或设计工具中的至少一种技能const { check, oneOf, validationResult } require(express-validator); app.post(/start-freelancing, oneOf([ check(programming_language).isIn([javascript, java, php]), check(design_tools).isIn([canva, photoshop, gimp]) ]), (req, res, next) { try { validationResult(req).throw(); // 校验通过继续处理 res.json(...); } catch (err) { // 用户两种技能都没有 res.status(400).json(...); } });分组语义如果数组的某个元素本身是校验链数组则该组内所有链必须同时通过该组才被视为有效// 受保护路由必须满足二者之一 // 1) 同时提供 username 与 password // 2) 提供 access_token app.post(/protected/route, oneOf([ [ check(username).exists(), check(password).exists() ], check(access_token).exists() ]), someRouteHandler);执行模型oneOf中各组校验链之间并行执行而单条链内部的执行仍然遵循check()中定义的串行规则。源码实现oneOf 的判定流程在 one-of.ts 中oneOf的实现要点它构建一个替身上下文surrogateContext内部塞入一个空操作的dummyItem以保证上下文可运行每条链或链组通过runAllChains(req, group, { dryRun: true })以干跑dryRun模式并行执行只收集错误、不真正修改请求判定逻辑是allErrors.some(groupErrors groupErrors.length 0)——只要存在一组没有字段错误整体即成功只有在其整组都有效时链中的数据才会被合并进替身上下文注释引用了 issue #536oneOf中的数据只有在整组有效时才能提供给例如matchedData()使用否则该组失败的数据不会泄露全部失败时默认以grouped方式在替身上下文添加一个alternative_grouped错误nestedErrors按组嵌套源码中还支持通过options.errorType切换为flat拍平所有子错误或least_errored只保留错误最少的组等策略最后通过new ContextRunnerImpl(surrogateContext).run(req, opts)完成最终运行。buildCheckFunction(locations)定制你的字段查找位置buildCheckFunction是面向高级定制场景的工厂函数locations一个请求位置数组可取body、cookies、headers、params、query中的任意多个返回值一个check()的变体只从给定的请求位置取字段。典型场景是某个字段可以出现在两个位置之一只要满足一处即可const { buildCheckFunction } require(express-validator); const checkBodyAndQuery buildCheckFunction([body, query]); app.put(/update-product, [ // id 可以位于 req.body 或 req.query且必须是一个 UUID checkBodyAndQuery(id).isUUID() ], productUpdateHandler);源码实现见 validation-chain-builders.tsexport function buildCheckFunction(locations: Location[]) { return (fields?: string | string[], message?: FieldMessageFactory | ErrorMessage) baseCheck(fields, locations, message); }它只是把locations预先绑定到内部baseCheck即 check.ts 中真正的实现上。而前面介绍的check、body、cookie、header、param、query六个官方入口全部是这个工厂的产物——理解了buildCheckFunction就等于理解了整组 API 的生成原理。错误消息的兜底层级与动态消息理解check([field, message])中的message参数需要同时了解错误消息的优先级层级详见 自定义错误消息校验器级最高优先级通过.withMessage()为单个校验器指定消息自定义校验器级自定义校验器 throw 或 reject 的值直接作为该字段错误消息字段级兜底check(field, 消息)中的第二参数仅在校验器未指定自己的消息时生效默认兜底值为Invalid value。message参数支持动态消息工厂写法——任何支持消息的位置都可传函数(value, { req, location, path }) message便于接入 i18n 翻译库oneOf的消息函数则只接收({ req })因为此时不存在单一字段值与位置。完整示例组合使用多类校验入口将上述 API 组合到一条真实路由中可以直观看到各自的分工const express require(express); const { check, body, query, param, checkSchema, oneOf, validationResult, } require(express-validator); const app express(); app.use(express.json()); // 1) check跨位置校验 字段级兜底消息 app.post(/register, check(email, invalid email).isEmail(), check(password, password too weak) .isLength({ min: 8 }) .matches(/\d/).withMessage(password must contain a number), (req, res) { const errors validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); res.json({ ok: true }); }); // 2) checkSchema声明式批量校验/净化 app.put(/profile/:id, checkSchema({ id: { in: [params], isInt: true, toInt: true }, nickname: { optional: true, isLength: { options: { min: 2, max: 20 } } }, age: { in: [body], optional: { options: { nullable: true } }, isInt: { options: { min: 0 } } }, }), (req, res) { const errors validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); res.json({ ok: true }); }); // 3) oneOf多选一登录 app.post(/login, oneOf([ [body(username).exists(), body(password).exists()], body(access_token).isJWT(), ]), (req, res) { const errors validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); res.json({ ok: true }); }); app.listen(3000);小结与选型建议需求推荐入口校验单个/多个字段位置不限check()明确限定字段所在位置body()/cookie()/header()/param()/query()直接校验整个请求体字符串/数组/数字body()省略字段大量字段、希望声明式集中管理checkSchema()至少满足一组条件多选一oneOf()需要自定义字段查找位置组合buildCheckFunction([body, query])等这套 API 设计以check为单一核心、以buildCheckFunction为统一工厂、以checkSchema和oneOf分别覆盖批量声明与多选一两类高阶场景掌握了它们的参数、返回类型与执行语义即可在 Express 应用中灵活、精准地搭建校验层。赞分享后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载相关推荐express-validator 校验中间件 API 完全指南check、body、oneOf、checkSchema 与 buildCheckFunctionexpress validator 校验中间件 API 完全指南check、body、oneOf、checkSchema 与 buildCheckFuncti后端express-validator v6 校验中间件check / body / param / checkSchema / oneOf / buildCheckFunction完全指南express validator v6 校验中间件check / body / param / checkSchema / oneOf / buildChe后端express-validator 校验中间件 API 完全指南check、body、query、checkSchema、oneOf 与 buildCheckFunctionexpress validator 校验中间件 API 完全指南check、body、query、checkSchema、oneOf 与 buildCheck后端上一篇戴尔笔记本风扇调校完整教程DellFanManagement 从跑起来到阈值调优一次讲透下一篇创维e900v22c的CoreELEC完整安装指南30分钟从镜像写到可用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考