news 2026/10/10 5:14:44

express-validator v5.3.0 Filter API 完全指南:matchedData 数据抽取与 sanitize 系列清洗函数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
express-validator v5.3.0 Filter API 完全指南:matchedData 数据抽取与 sanitize 系列清洗函数
  • 后端

【免费下载链接】express-validator

An express.js middleware for validator.js.

项目地址:https://gitcode.com/gh_mirrors/ex/express-validator
点击查看免费下载

本篇技术指南围绕 express-validator v5.3.0 的Filter API展开,该 API 通过require('express-validator/filter')提供。文章核心覆盖两大能力:用matchedData()从请求中抽取已被checkAPI 校验过的数据并重组为干净对象,以及用sanitize()及其位置变体、buildSanitizeFunction()构建针对不同请求位置的清洗链。阅读完本文,你将掌握每个函数的参数语义、默认值、底层实现原理与实战用法,并能正确将其迁移到 v6/v7 的新式 API。

概述:Filter API 在 express-validator 中的定位

在 express-validator v5.3.0 中,代码按职责拆分为两个独立入口:

  • require('express-validator/check'):提供check、body、query等校验相关 API;
  • require('express-validator/filter'):提供matchedData、sanitize、sanitizeBody、sanitizeCookie、sanitizeParam、sanitizeQuery、buildSanitizeFunction等数据抽取与清洗相关 API。

Filter API 回答了两个常见问题:"校验通过后,如何方便地拿到一个只含合法数据的干净对象?"以及"如何在不使用整个express-validator中间件的情况下,单独对请求字段做清洗?"本文对应的原版文档位于仓库 website/versioned_docs/version-5.3.0/api-filter.md。

需要注意:在 v6.0.0 之后,express-validator/check与express-validator/filter两个入口均被废弃(会向控制台打印警告),所有 API 统一从express-validator主入口导入,详见 docs/migration-v5-to-v6.md。本文讲解的 API 语义在 v5.3.0 中即为如此,而其底层行为至今仍可在仓库源码src/matched-data.ts与src/express-validator.ts中得到印证。

matchedData(req[, options]):抽取已校验数据

matchedData是 Filter API 的核心函数。它的作用是:从请求中提取已被checkAPI 校验过的数据,并组装成一个对象返回。嵌套路径与通配符(wildcards)都会被正确处理。

函数签名与返回值

matchedData(req[, options])
  • req:Express 的 request 对象。
  • options(可选):一个对象,支持以下选项:
    • includeOptionals:设为true时,返回值包含被标记为 optional 的数据;默认false。
    • onlyValidData:设为false时,返回值将包含未通过校验字段的数据;默认true。
    • locations:一个数组,指定从哪些请求位置抽取数据。可接受的值包括body、cookies、headers、params和query;默认undefined,表示所有位置。
  • 返回值:由checkAPI 校验过的数据组成的对象。

基础示例

原文档给出了一个极具代表性的完整示例,覆盖了按位置抽取与全量抽取两种用法:

// Suppose the request looks like this: // req.query = { from: '2017-01-12' } // req.body = { to: '2017-31-12' } app.post('/room-availability', check(['from', 'to']).isISO8601(), (req, res, next) => { const queryData = matchedData(req, { locations: ['query'] }); const bodyData = matchedData(req, { locations: ['body'] }); const allData = matchedData(req); console.log(queryData); // { from: '2017-01-12' } console.log(bodyData); // { to: '2017-31-12' } console.log(allData); // { from: '2017-01-12', to: '2017-31-12' } });

可以看到:不传locations时,matchedData会把不同位置(query、body)的数据合并进同一个对象;传入locations数组后,则只输出指定位置的字段。

三个选项的完整语义

  1. includeOptionals(默认false)

    当一个字段链被标记为.optional(),且请求中没有该字段(值为undefined)时,该字段默认不会出现在matchedData的结果中。将includeOptionals设为true后,这些"缺省但可选"的字段也会被纳入结果(值为undefined或按 optional 规则判定)。

    从源码看,这一选项直接映射到Context.getData({ requiredOnly })的行为(src/matched-data.ts):当removeOptionals为true时,Context会按字段的optional设置过滤掉undefined、null(optional === 'null'时)或 falsy(optional === 'falsy'时)的值,过滤逻辑见 src/context.ts。

  2. onlyValidData(默认true)

    默认情况下,只要某个字段在对应位置存在校验错误(error.type === 'field'且location、path匹配),该字段的值就不会被返回。当设为false时,即使字段未通过校验也会被包含进结果。

    对应源码中的createValidityFilter(src/matched-data.ts):它为false时直接放行所有数据,为true时则检查该字段在 context 的errors数组中是否存在匹配的 field 类型错误。

  3. locations(默认undefined,即全部位置)

    限定抽取范围。源码中createLocationFilter(src/matched-data.ts)的实现很直白:locations为空数组时不过滤任何位置;否则只保留locations.includes(field.location)的字段。位置的可选值在 src/base.ts 中定义为'body' | 'cookies' | 'headers' | 'params' | 'query'。

底层工作原理

matchedData的读取路径在 src/matched-data.ts 中非常清晰,可以总结为一条流水线:

  1. 从req的express-validator#contexts键(源码常量contextsKey,见 src/base.ts)取出校验中间件在运行时写入的全部Context对象;
  2. 用flatMap将每个 Context 中的字段实例(FieldInstance)连同其所属 Context 展开成扁平列表;
  3. 用validityFilter过滤掉有校验错误的字段;
  4. 用locationFilter过滤掉不在指定位置的字段;
  5. 最后通过 lodash 的_.set(state, instance.path, instance.value)按字段路径重组出嵌套对象——这正是嵌套路径(如user.name)与通配符(如foo.*)能被正确还原成层级结构的原因。

这一实现还被ExpressValidator类的实例方法matchedData复用(src/express-validator.ts),该方法注释明确说明它是matchedData的快捷方式,行为完全一致。

由测试用例验证的行为细节

仓库中的 src/matched-data.spec.ts 覆盖了文档提到的全部选项组合,可直接作为行为契约:

  • 未运行任何校验/清洗链时返回{}(matchedData({})不会抛错);
  • 默认情况下只包含有效且非 optional的数据:check(['foo', 'bar', 'baz']).optional().isInt()作用于{ headers: { foo: 'bla', bar: '123' } }时,结果只有{ bar: '123' }——foo因未通过isInt被剔除,baz因 optional 且缺失被剔除;
  • 通配符校验结果会被正确合并,如check(['foo.*', '*.*.qux']).isInt()返回嵌套的{ foo: [1, 2, 3], bar: { baz: { qux: 4 } } };
  • 在oneOf()中失败的链组,其字段即使本身值合法,也不会被包含——避免把"来自失败分支"的数据当作可信数据;
  • includeOptionals: true时,缺失的 optional 字段baz会出现在结果中;
  • onlyValidData: false时,未通过isInt的foo: 'bla'也会被返回;
  • locations: ['params', 'query']时,只返回params与query位置的数据,headers中的数据被忽略。

sanitize(fields):创建通用清洗链

sanitize(fields)
  • fields:一个字段名字符串或字符串数组。
  • 返回值:一个 Sanitization Chain。

sanitize为单个或多个字段创建清洗链,这些字段可以位于以下任意请求对象中:

  • req.body
  • req.cookies
  • req.params
  • req.query

注意:req.headers在 v5.3.0 中暂不支持。

关键语义:如果某个字段在多个位置同时存在,那么该字段在所有位置的实例都会被清洗。

一个典型的组合用法是"清洗链 + 中间件执行",例如对用户输入做转义与去空格:

const { sanitizeBody } = require('express-validator/filter'); app.post('/contact-us', (req, res) => { sanitizeBody('message').escape().trim(); // ...后续处理 });

v5 时代清洗链通常依赖全局中间件或直接执行;迁移到 v6 后,需要改为await sanitize('message').escape().trim().run(req),并在路由中使用express-validator主入口导入,参见 docs/migration-v5-to-v6.md。

位置限定变体:sanitizeBody/sanitizeCookie/sanitizeParam/sanitizeQuery

四个变体与sanitize(fields)的唯一区别在于清洗位置被锁定:

函数作用位置等价写法
sanitizeBody(fields)仅req.bodybuildSanitizeFunction(['body'])(fields)
sanitizeCookie(fields)仅req.cookiesbuildSanitizeFunction(['cookies'])(fields)
sanitizeParam(fields)仅req.paramsbuildSanitizeFunction(['params'])(fields)
sanitizeQuery(fields)仅req.querybuildSanitizeFunction(['query'])(fields)

它们与校验侧body()、cookie()、param()、query()的对应关系一致——在 v5.3.0 的 api-check.md 中,check系列同样按位置拆分。

清洗动作通过 Sanitization Chain 执行,链上的每个清洗器在运行时被封装为Sanitization上下文项(src/context-items/sanitization.ts):数组值会被逐元素清洗,字符串化(toString)后交给 validator.js 的标准清洗器,结果写回 Context 的 dataMap,供后续读取或matchedData使用。

buildSanitizeFunction(locations):自定义位置组合

buildSanitizeFunction(locations)
  • locations:一个请求位置数组,可包含body、cookies、params或query中的任意组合。
  • 返回值:一个sanitize()的变体,只清洗传入的这些位置。

buildSanitizeFunction让我们不必为每种组合手写位置判断,而是直接产出绑定了位置集合的清洗函数。原文档示例非常实用:

const { buildSanitizeFunction } = require('express-validator/filter'); const sanitizeBodyAndQuery = buildSanitizeFunction(['body', 'query']); app.put('/update-product', [ // id 无论出现在 req.body 还是 req.query,都会被转换为 int sanitizeBodyAndQuery('id').toInt() ], productUpdateHandler)

当业务上允许某个字段"既可能在 body 中,也可能在 query 中"(例如 REST 中 id 可来自路径查询参数)时,buildSanitizeFunction(['body', 'query'])一次即可覆盖两个位置,这正是sanitize(fields)"多位置同时清洗"语义的灵活运用。

常见问题与注意事项

  • req.headers不被sanitize支持:v5.3.0 的 Filter API 中,清洗侧无法覆盖 headers;如果需要清洗 headers 中的数据,只能在校验侧借助header()与自定义逻辑处理。相比之下,校验侧check系列是支持 headers 的。
  • 多位置同名字段:字段若同时出现在 body 与 query,sanitize(fields)会清洗所有实例,这与check中"多位置同时校验"的语义(见 api-check.md)保持一致;底层Context.getData在多位置、多实例场景下还会做去重与"至少包含一个用于报错"的兜底处理(src/context.ts)。
  • matchedData依赖校验链先运行:matchedData读取的是校验中间件写入req的 contexts 数据(express-validator#contexts)。如果没有任何check链运行过,返回空对象({}),不会抛错——这一点有 src/matched-data.spec.ts 的测试保证。
  • v6+ 迁移:express-validator/filter入口在 v6 起废弃,统一改为require('express-validator');同时sanitize系列清洗链需要追加.run(req)才会真正执行,详见 docs/migration-v5-to-v6.md。

小结

Filter API 是 express-validator v5.3.0 中"数据出口"与"数据清洗"的一体化工具:

  • matchedData(req, options)以三个选项(includeOptionals、onlyValidData、locations)精确控制返回的数据范围,内部借助express-validator#contexts存储、Context.getData过滤与 lodash_.set重组,天然支持嵌套路径与通配符;
  • sanitize(fields)及其四个位置变体(sanitizeBody、sanitizeCookie、sanitizeParam、sanitizeQuery)把清洗链绑定到指定请求位置,buildSanitizeFunction(locations)则进一步支持任意位置组合。

这些行为的正确性在仓库测试 src/matched-data.spec.ts 中有完整覆盖,读者可据此验证本文结论,并在升级到 v6/v7 时无缝迁移 API 形态。

  • 后端

【免费下载链接】express-validator

An express.js middleware for validator.js.

项目地址:https://gitcode.com/gh_mirrors/ex/express-validator
点击查看免费下载
上一篇:在hub-proxy项目中实现GitHub资源缓存中转的技术解析
下一篇:Microsoft-Office-For-MacOS自动化脚本:一键完成安装配置流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 5:14:42

卷积核、FIR滤波器与LTI系统——一回事

禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》 三、四、五 三章之间的关系 3\S 33卷积核(空域滤波器) 4\S 44FIR滤波器(频域滤波器设计) 5\S 55LTI系统(…

作者头像 李华
网站建设 2026/10/10 5:13:08

Go 1.27.1 结构体字面量任意选择器实战:重构高性能协议编解码器

在构建单机吞吐百万 QPS 的高性能微服务网关、自研二进制 RPC 协议或长连接消息中继服务时,网络协议的**序列化与反序列化(编解码 Codec)**始终是整个处理流水线中执行频次最高的底层路径。 在长期的 Go 语言网络编程实践中,工程师…

作者头像 李华
网站建设 2026/10/10 5:13:03

免费降AI率实战:从95%到10%的文本去机器化改写指南

你可能已经遇到了这个场景:辛辛苦苦写完的稿子,往检测系统里一丢,页面直接弹出一行刺眼的“AIGC疑似率高”,有的平台甚至直接标到95%。后台留言里最近全是这类问题,从毕业论文到软著材料,从课题申报书到结题…

作者头像 李华
网站建设 2026/10/10 5:12:59

全国大漠健身运动大赛

简介全国大漠健身运动大赛由国家体育总局群众体育司指导,国家体育总局社会体育指导中心主办。历届全国大漠健身运动大赛届数年份时间冠名地点备注第七届20267月3日-7月7日中卫市沙坡头景区全国大漠健身运动会届数年份时间冠名地点备注第六届20247月6日-7月9日沙坡头…

作者头像 李华
网站建设 2026/10/10 5:12:59

三数之和双指针解法:排序去重与O(n²)优化实践

1. 题目理解与整体思路1.1 三数之和到底是什么问题先把这个题说人话。给定一个整数数组nums,让你找出所有三个数相加等于 0 的组合,而且要求返回的三元组不重复。比如[-1, 0, 1, 2, -1, -4],结果就是[-1, -1, 2]和[-1, 0, 1],注意…

作者头像 李华
网站建设 2026/10/10 5:11:50

OpenHarmony文本处理:用字符串分割实现结构感知的行数统计

最近在做一个 OpenHarmony 上的文本处理小工具,本来想着写个“统计某个纯文本有多少行”的功能,分分钟就能搞定。结果往下一做才发现,这个“行数统计”远没有想象中那么简单:Windows 和 macOS 的换行符不一样,空行算不…

作者头像 李华