后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载checkExact()是 express-validator 提供的一种反向校验中间件传统校验只关心声明过的字段是否符合规则而它负责检查请求中是否出现了没有对应校验链validation chain的未知字段一旦发现即以unknown_fields错误类型上报。本文基于仓库中的官方文档 check-exact.md 并结合 src/middlewares/exact.ts 源码完整讲解其签名、known fields 语义、locations选项、与checkSchema()的配合、手动运行方式以及底层的未知字段探测算法读完即可在自己的 express.js 路由中落地白名单式的精确字段校验。checkExact()是什么签名与核心语义checkExact()的完整类型签名如下checkExact( chains?: ValidationChain | ValidationChain[] | (ValidationChain | ValidationChain[])[], options?: { locations?: Location[], message?: any } ): Middleware ContextRunner它返回的对象同时是两种角色的复合体一个 express.js中间件Middleware可直接挂载到路由上一个实现了ContextRunner接口的运行器可以手动调用.run(req)获取校验结果。已知字段known fields的判定规则checkExact()会检查请求中是否恰好只包含那些拥有与之关联的 validation chain 的字段。文档中明确了核心语义一个字段被checkExact()视为已知当且仅当在checkExact()运行之前已经为它指定过校验链。这句话包含两个关键限定时间维度只有先于checkExact()执行过的校验链才会计入已知集合。这是本 API 最容易踩坑的地方详见下文重要警告一节。空间维度若把校验链作为参数传给checkExact()那么这些链会在checkExact()运行时一并执行且它们所瞄准的字段会被额外计入已知集合——即已知字段 之前声明的链 本次传入的链。从源码看src/middlewares/exact.ts 的run函数正是这么实现的先通过runAllChains(req, chainsArr)运行传入的链再从请求对象上挂载的contextsKeyexpress-validator#contexts见 src/base.ts读取此前所有链注册的 context把每个 context 的fields按locations聚合进fieldsByLocation映射表形成已知字段清单。一个完整的中间件用法以下示例中name、email、password都是req.body中的已知字段请求中出现的任何其他字段都会被判定为未知app.post( /signup, // All of name, email and password are known fields in req.body. Everything else is unknown. body(name).notEmpty(), checkExact([body(email).isEmail(), body(password).isLength({ min: 8 })], { message: Too many fields specified, }), (req, res) { // Handle request }, );注意这里email和password的校验链是作为参数传入checkExact()的因此它们既会被正常执行isEmail()、isLength()照常生效其目标字段又会被自动视为已知。发现未知字段时会发生什么如果请求中存在未知字段checkExact()会向请求添加一个类型为unknown_fields的UnknownFieldsError错误默认消息为Unknown field(s)。其结构定义于 src/base.tstype UnknownFieldsError { type: unknown_fields; msg: any; fields: { path: string; location: Location; value: any }[]; };fields列出了所有未知字段的路径path、所在位置location与实际值value该错误会与其他校验错误一样被validationResult(req)收集可以配合.array()、.mapped()等方法统一处理参见 validation-result.md默认消息可通过options.message覆盖若传的是函数则必须是UnknownFieldMessageFactory类型详见下文。重要警告checkExact()必须是最后一个验证中间件官方文档用:::caution强调了一个极易踩中的陷阱checkExact()必须是请求中最后一个运行的验证中间件否则它会把后续才拥有校验链的字段误判为未知字段。原因正是已知字段判定的时间维度checkExact()只会把在它之前注册过的 context 视为已知。下面这个反例中email是已知字段但subscribe不是——因为它的校验链排在checkExact()之后app.post( /newsletter/subscription, body(email).isEmail(), checkExact(), // 此时 subscribe 还没有校验链会被当作未知字段 body(subscribe).isBoolean(), (req, res) { // Handle request }, );当请求中带了subscribe字段时checkExact()会生成unknown_fields错误尽管业务上你确实打算校验它。从源码可以印证这一行为run函数遍历internalReq[contextsKey]即已经挂到请求上的 context 列表来收集已知字段checkExact()之后才运行的链其 context 自然不在其中。因此实践中的铁律是把所有字段校验链放在前面checkExact()永远放最后。若用body()/query()等链构建器声明字段请确保它们全部位于checkExact()之前或作为参数传入。locations选项控制检查范围checkExact()默认只检查三个请求位置location可通过options.locations自定义默认值仅包含body、params和query。options.locations范围之外的未知字段不会被报告。type Location body | cookies | headers | params | query;源码 src/middlewares/exact.ts 中的默认值为opts?.locations || [body, params, query]注释也点明了设计意图默认不检查cookies和headers以避免把用户正常请求判为非法。官方文档给出了三个理由HTTP 规范定义了大量 headers用途与产生原因各异。你不可能为了通过checkExact()而把所有这些 header 全部声明为已知字段否则会带来大量误报false negatives 的反面——合法请求被拒绝浏览器和代理会不断引入新 header需要已知的 header 清单会无限膨胀让checkExact()在 header 上难以稳定工作浏览器默认会自动携带 cookies随每个请求发送而页面上的 JS 广告或分析脚本通常会在宿主站点创建 cookie这会让针对 cookies 的严格检查非常恼人。基于以上原因req.cookies与req.headers默认不参与未知字段检查如果你确实需要严格管控它们再通过locations显式加入。四类实战示例官方文档提供了四个典型场景的示例覆盖了checkExact()的主要使用形态。示例一不带输入校验链如果路由中的字段已经由前面的链声明过可以直接传空数组app.post( /signup, body(email).isEmail(), body(password).isLength({ min: 8 }), checkExact([], { message: Only email and password are allowed }), (req, res) { // Handle request }, );此时checkExact()会把email、password视为已知因为前面的链已经注册了 contextreq.body、req.query、req.params中的任何其他字段都会触发UnknownFieldValidationError错误消息被自定义为Only email and password are allowed。示例二与checkSchema()组合checkSchema()返回的是一个校验链列表因此可以直接作为chains参数传给checkExact()app.post( /signup, checkExact( checkSchema({ email: { isEmail: true }, password: { isLength: { options: { min: 8 } } }, }), ), (req, res) { // Handle request }, );这一组合非常契合白名单式接口设计schema 同时声明了字段的校验规则和允许出现的边界且源码中的CheckExactInput类型src/middlewares/exact.ts允许传入单个链、链数组或链与链数组混合的数组checkSchema()返回的链列表正好属于第二种。示例三只检查req.body若你只关心 body 中的未知字段其他位置如 query、params允许自由出现额外字段app.post( /signup, body(email).isEmail(), body(password).isLength({ min: 8 }), checkExact([], { locations: [body] }), (req, res) { // Handle request }, );设置locations: [body]后检查范围被收窄到req.bodyreq.query、req.params等位置的未知字段将不会被报告。测试用例 src/middlewares/exact.spec.ts 也验证了这一点当设置locations: [headers]时只会从req.headers中发现未知字段。示例四手动运行ContextRunner 模式checkExact()返回的中间件天然适合挂载到 express.js 路由但它同时也实现了ContextRunner接口可以像校验链一样手动运行app.post( /signup, body(email).isEmail(), body(password).isLength({ min: 8 }), async (req, res) { const result await checkExact().run(req); if (result.isEmpty()) { console.log(No unknown fields in the request); } }, );ContextRunner的接口定义为run(req, options?): PromiseResult见 src/chain/context-runner.ts返回的Result可用.isEmpty()、.array()等方法判断。从源码看checkExact()通过Object.assign(middleware, { run })把run函数同时挂到中间件对象上src/middlewares/exact.ts这正是既是中间件、又能手动运行的机制来源。更完整的自定义运行器模式可参考 manually-running.md。UnknownFieldMessageFactory定制未知字段错误消息当options.message传的是函数时它必须符合UnknownFieldMessageFactory类型type UnknownFieldMessageFactory ( unknownFields: UnknownFieldInstance[], opts: { req: Request }, ) any;该类型定义于 src/base.ts接收两个参数unknownFields本次发现的所有未知字段实例列表每个实例包含path字段路径、location所在位置与value字段值opts包含当前req的上下文对象。典型用法如下可以按字段维度生成更具体的错误信息checkExact([body(name).notEmpty(), body(email).isEmail()], { message: fields { const [field] fields; return Unknown field ${field.path} in ${field.location} with value ${field.value}; }, });在 src/context.ts 的addError中可以看到unknown_fields类型错误的消息正是通过typeof msg function ? msg(opts.fields, { req: opts.req }) : msg来解析的——传入函数时会以fields和{ req }为参数调用返回的值会成为msg。底层原理未知字段是如何被探测出来的checkExact()的核心探测逻辑不在exact.ts本身而在 src/field-selection.ts 的selectUnknownFields函数。已知字段的树形建模算法先把所有已知字段路径构建成一棵前缀树Tree例如已知字段foo.bar会生成{ foo: { bar: { : {} } } }这样的嵌套结构。随后对每个受检位置的请求数据做深度优先搜索findUnknownFieldssrc/field-selection.ts凡是树中没有任何分支覆盖的键即被判定为未知。该算法对以下三种覆盖情形做了特殊处理因此表现与直觉一致整枝校验若某个分支以空字符串键结尾如{ foo: { : {} } }即foo被整体校验则其下的所有子字段都不算未知路径单独校验foo.bar被单独校验过则该路径本身不算未知通配符覆盖*单层通配与**globstar多层通配覆盖到的路径均视为已知。关键边界行为从findUnknownFields的源码还可以推断出几个值得注意的边界行为非对象请求体如果req.body是字符串等原始值且没有被任何链校验treePath为空且无 globstar 分支整个请求体会被当作未知字段上报通配符残留foo.**.bar这类 globstar 路径只会覆盖匹配的叶子未命中的叶子仍会被标记为未知多分支合并去重当多个分支如foo与foo.*.bar同时存在时更全面的分支foo会使较窄分支的未知结论被抑制避免重复或误报路径重建未知字段的path由reconstructFieldPathsrc/field-selection.ts重建数字段会被包装成数组下标语法如foo[0].bar包含特殊字符如.的键会被包装成foo[bar.baz].qux与 JS 对象访问语法保持一致。传入链的执行顺序checkExact()内部通过 src/utils.ts 的runAllChains运行传入的链。该函数对带请求级bail的链做了顺序处理遇到 bailed 链时会先等待之前的链全部完成若该链结果非空则中断后续链的执行从而保证错误聚合结果不被扭曲。测试验证源码如何保证行为正确仓库中的 src/middlewares/exact.spec.ts 为上述行为提供了完整的测试覆盖可以作为理解checkExact()语义的活的文档不同链参数形态单条链、链数组、链与链数组混合数组都能正确发现未知字段并只生成一个unknown_fields错误spec 第 5-25 行继承先前链先手动运行check(banana).run(req)再运行checkExact()banana会被视为已知而apple被报为未知spec 第 27-38 行——这正是已知字段时间维度的实证默认位置默认只检查body、params、query而cookies、headers中的字段即使存在也不会被报告spec 第 54-73 行零误报所有字段都有对应链时result.isEmpty()为true不会生成任何错误spec 第 75-82 行中间件形态checkExact([])可直接作为中间件调用并正确进入next()spec 第 84-89 行。小结与推荐实践checkExact()为 express-validator 补齐了请求字段白名单这一环与传统的字段规则校验形成互补。综合文档与源码推荐的落地姿势是位置放在最后确保checkExact()是路由中最后一个验证中间件或把其余字段链作为参数传入默认位置即可大多数场景下保持默认的body、params、query检查范围避免对 headers/cookies 误伤配合checkSchema()用 schema 同时声明字段规则与允许边界代码最简洁自定义错误消息通过UnknownFieldMessageFactory生成包含path、location、value的详细错误便于客户端定位必要时手动运行利用ContextRunner接口在自定义中间件中灵活控制执行时机与结果处理。更完整的内容可继续阅读同一版本文档中的 check.md、validation-result.md 与 misc.md以及源码 src/middlewares/exact.ts 和 src/field-selection.ts 中的实现细节。赞分享后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载相关推荐express-validator字段选择指南精准定位请求数据express validator字段选择指南精准定位请求数据 引言 在Web开发中处理客户端提交的数据是核心任务之一。express validator作后端Express-Validator 字段选择指南精准定位请求数据Express Validator 字段选择指南精准定位请求数据 引言 在Web开发中处理用户输入数据是至关重要的一环。Express Validator作后端Kubernetes 排障实战指南基于 claude-skills 技能的 kubectl 调试命令、故障根因与诊断工具全解Kubernetes 排障实战指南基于 claude skills 技能的 kubectl 调试命令、故障根因与诊断工具全解 本文是 claude skill后端上一篇从零训练目标检测器MMDetection 中 Rethinking ImageNet Pre-trainingScratch 训练完整指南下一篇三步告别广告和登录验证kill-doc脚本让你轻松下载各大文库文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考