express-validator 内置清洗器(Sanitizers)完全指南:从 trim 到 normalizeEmail 的字段值转换实战
后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载本篇文章聚焦 express-validator 验证链中的内置清洗器standard sanitizers体系系统讲解_sanitizers.md文档所覆盖的全部清洗方法——从trim、blacklist等字符串清洗到toInt、toDate等类型转换再到normalizeEmail这类针对特定场景的规范化工具。结合本仓库 src/chain/sanitizers.ts 与 src/context-items/sanitization.ts 的源码实现你将理解清洗器如何把处理后的值写回请求对象、如何处理数组与字符串转换并能在真实路由中熟练组合清洗器与校验器写出安全、整洁、类型正确的请求处理代码。清洗器是什么与校验器的区别在 express-validator 中验证链Validation Chain由body()、query()、param()、header()等检查函数创建链上可挂三类方法校验器Validators判断字段值是否符合预期格式不合法则记录错误清洗器Sanitizers转换字段值清除噪声、转换为正确的 JavaScript 类型或提供基础的安全防护修饰器Modifiers改变链的运行行为如optional()、bail()。清洗器最关键的特性是它会将清洗后的新值持久化回请求对象。这意味着下游的其他中间件、你自己的路由处理器甚至后续的校验器都能直接使用被清洗后的值。这一行为在 docs/guides/validation-chain.md 中明确说明并由 src/context-items/sanitization.ts 中的context.setData(path, newValue, location)调用实现。内置清洗器的来源validator.jsexpress-validator 内置的“标准清洗器”standard sanitizers绝大部分直接来自 validator.js 这一专精于字符串校验的 JavaScript 库。这些方法在类型层面被定义为// src/base.ts export type StandardSanitizer (input: string, ...options: any[]) any;由于 validator.js 只处理字符串express-validator 在执行标准清洗器前会把字段值先转换为字符串转换规则见 docs/guides/validation-chain.md为Date对象使用其toISOString()的返回值null、undefined、NaN转换为空字符串实现了自定义toString()的对象使用该方法的返回值其他对象使用默认的toString()布尔值、数字等其余值按原样转为字符串。此外数组的每个元素会被独立清洗。例如对req.body.ids中的数组逐项调用toInt()每个元素都会单独转换。全部内置清洗器速查表docs/api/validator/_sanitizers.md 列出了标准清洗器的完整 TypeScript 签名对应接口定义见 src/chain/sanitizers.ts方法签名作用blacklistblacklist(chars: string)删除值中出现在chars中的字符escapeescape()将、、、、等字符转为 HTML 实体unescapeunescape()将 HTML 实体还原为原始字符ltrimltrim(chars?: string)去除字符串左侧空白或指定字符集rtrimrtrim(chars?: string)去除字符串右侧空白或指定字符集trimtrim(chars?: string)去除字符串两侧空白或指定字符集stripLowstripLow(keep_new_lines?: boolean)移除 ASCII 控制字符传true保留换行normalizeEmailnormalizeEmail(options?)规范化邮箱地址小写化、去子地址等toBooleantoBoolean(strict?: boolean)将字符串true/false等转为布尔值toDatetoDate()将可解析的字符串转为Date对象toFloattoFloat()转为浮点数toInttoInt(radix?: number)按进制转为整数whitelistwhitelist(chars: string)仅保留chars中出现的字符注_sanitizers.md仅列出标准清洗器除此之外Sanitizers 接口 还包含customSanitizer()、default()、replace()三个自定义清洗方法以及toArray()、toLowerCase()、toUpperCase()三个由 express-validator 自身实现的辅助清洗器下文会一并补充。字符串清洗类方法详解trim()/ltrim()/rtrim()去空白这三个方法在 src/chain/sanitizers-impl.ts 中直接透传给 validator.jsltrim(chars?: string) { return this.addStandardSanitization(validator.ltrim, chars); } rtrim(chars?: string) { return this.addStandardSanitization(validator.rtrim, chars); } trim(chars?: string) { return this.addStandardSanitization(validator.trim, chars); }trim()去除两侧空白ltrim()/rtrim()分别只处理左侧/右侧可选参数chars用于指定自定义的去字符集合默认去空白字符非字符串值会先按上文规则转成字符串再清洗。典型用法把用户输入的邮箱、用户名在保存前统一去空白app.post(/signup, body(email).trim().isEmail(), body(username).trim().notEmpty(), handler);顺序陷阱重要清洗器与校验器的调用顺序会影响结果。对比以下两种写法出自 docs/guides/validation-chain.md// 先校验再清洗全是空格的 通过 notEmpty 校验随后被 trim 成空串——误判通过 query(search_query).notEmpty().trim(); // 先清洗再校验空格被去除后才判断是否为空——逻辑正确 query(search_query).trim().notEmpty();因此涉及依赖清洗结果判断的校验如notEmpty()、isEmail()务必把清洗器放在校验器之前。blacklist()/whitelist()字符黑名单与白名单blacklist(chars)删除值中所有出现在chars中的字符whitelist(chars)只保留chars中出现的字符其余全部删除。例如移除字符串中的所有数字或只保留十六进制字符body(hex).whitelist(0123456789abcdefABCDEF).toLowerCase();escape()/unescape()HTML 实体互转escape()将、、、、替换为对应的 HTML 实体是防 XSS 的基础手段unescape()执行反向操作把实体还原回字符。值得强调的是express-validator 的官方立场是不建议用escape()代替真正的 HTML 转义库如escape-html它更适合对字符串做轻度处理需要输出到 HTML 时请使用经过充分测试的转义方案。stripLow()移除控制字符stripLow(keep_new_lines?: boolean)用于移除值中的 ASCII 控制字符0-31 与 127。传入true时保留换行符适合清理用户输入的多行文本同时保留其段落结构body(comment).stripLow(true).trim();normalizeEmail()邮箱地址规范化normalizeEmail(options?)是签名最复杂的标准清洗器其完整选项见 docs/api/validator/_sanitizers.md为normalizeEmail(options?: { all_lowercase?: boolean; gmail_lowercase?: boolean; gmail_remove_dots?: boolean; gmail_remove_subaddress?: boolean; gmail_convert_googlemaildotcom?: boolean; outlookdotcom_lowercase?: boolean; outlookdotcom_remove_subaddress?: boolean; yahoo_lowercase?: boolean; yahoo_remove_subaddress?: boolean; icloud_lowercase?: boolean; icloud_remove_subaddress?: boolean; yandex_convert_yandexru?: boolean; }): ValidationChain各选项作用all_lowercase将整个邮箱地址转为小写gmail_lowercase仅对 Gmail 地址小写化Gmail 不区分大小写gmail_remove_dots去除 Gmail 地址中的点号john.doegmail.com→johndoegmail.com二者是同一邮箱gmail_remove_subaddress去除 Gmail 的子地址johnnewslettergmail.com→johngmail.comgmail_convert_googlemaildotcom将googlemail.com统一为gmail.comoutlookdotcom_lowercase/outlookdotcom_remove_subaddress针对 Outlook.com 的小写化与子地址去除yahoo_lowercase/yahoo_remove_subaddress针对 Yahoo 的小写化与子地址去除icloud_lowercase/icloud_remove_subaddress针对 iCloud 的小写化与子地址去除yandex_convert_yandexru将yandex.ru统一为ya.ru二者等价。典型场景注册/登录接口中先trim()再normalizeEmail()再isEmail()保证同一个人无论用John.DoeGmail.com还是johndoegmail.com注册最终落库都是同一规范化地址避免重复账号app.post(/signup, body(email).trim().normalizeEmail({ all_lowercase: true }).isEmail(), handler, );类型转换类方法详解toInt()/toFloat()toInt(radix?: number)按指定进制默认十进制将字符串转为整数toFloat()转为浮点数。实现中它们把radix作为选项透传给 validator.js见 src/chain/sanitizers-impl.tstoInt(radix?: number) { return this.addStandardSanitization(validator.toInt, radix); }典型用法把查询参数、路径参数从字符串转为数字再参与业务逻辑app.get(/product/:id, param(id).toInt(), (req, res) { // req.params.id 现在是 number 而不是 string });toBoolean()toBoolean(strict?: boolean)将字符串转为布尔值非严格模式默认true、1、yes等常见真值字符串转true空串与0、false、no等转false严格模式strict: true仅true转true、false转false其余返回false。toDate()toDate()尝试把字符串解析为Date对象解析失败时结果为null需配合后续的isDate()等校验器做兜底判断。由 express-validator 自身实现的辅助清洗器除标准清洗器外Sanitizers 接口 还包含四个由 express-validator 直接实现的方法官方 API 文档位于 docs/api/validation-chain.mdtoArray()将值转换为数组已是数组则原样返回undefined转为空数组[]其他值包装成单元素数组。源码实现// src/chain/sanitizers-impl.ts toArray() { return this.customSanitizer( value (value ! undefined ((Array.isArray(value) value) || [value])) || [], ); }toLowerCase()/toUpperCase()仅当值为字符串时执行大小写转换非字符串则不做任何处理toLowerCase() { return this.customSanitizer(value (typeof value string ? value.toLowerCase() : value)); }自定义清洗器customSanitizer() / default() / replace()customSanitizer()签名customSanitizer(sanitizer: (value, { req, location, path, pathValues }) any): ValidationChain函数接收当前字段值与元信息对象包含req、location、path、pathValues返回值将成为字段新值。官方示例见 docs/api/validation-chain.mdapp.post(/object/:id, param(id).customSanitizer((value, { req }) { // 在该应用中用户使用 MongoDB 风格的对象 ID其余则为数字 return req.query.type user ? ObjectId(value) : Number(value); }), (req, res) { // 处理请求 });default()签名default(defaultValue: any): ValidationChain。当字段值为空串、null、undefined或NaN时用默认值替换app.post(/, body(username).default(foo), (req, res, next) { // bar bar // foo // undefined foo // null foo // NaN foo });实现上它复用了customSanitizerdefault(default_value: any) { return this.customSanitizer(value [undefined, null, NaN, ].includes(value) ? _.cloneDeep(default_value) : value, ); }注意当默认值是对象时会被深拷贝_.cloneDeep避免多个请求之间共享引用。replace()签名replace(valuesFrom: any[], valueTo: any): ValidationChain。当前值命中valuesFrom列表时替换为valueTo单个非数组值会被自动包装为数组替换值同样会被深拷贝app.post(/, body(username).replace([bar, BAR], foo), (req, res, next) { // bar_ bar_ // bar foo // BAR foo });底层原理Sanitization 如何执行并写回值标准清洗器与自定义清洗器最终都体现为验证链上下文中的一个ContextItem。相关实现位于 src/context-items/sanitization.tsasync run(context: Context, value: any, meta: Meta) { if (this.custom) { const newValue await runCustomSanitizer(); // 自定义直接调用可为异步 context.setData(path, newValue, location); return; } const values Array.isArray(value) ? value : [value]; const newValues values.map(value (this.sanitizer as StandardSanitizer)(this.stringify(value), ...this.options), ); // 若原始值是单个值取数组首元素写回 context.setData(path, values ! value ? newValues[0] : newValues, location); }从源码可以提炼出三个关键机制字符串化标准清洗器执行前通过stringify内部工具函数见 src/utils.ts把值转为字符串这正对应上文“validator.js 只处理字符串”的约定数组逐元素处理数组值的每个元素独立清洗但清洗结果若为单元素包装数组则只把第一个元素写回保证body(id).toInt()这类链在值不是数组时得到的是标量而非[数字]自定义清洗器可异步customSanitizer分支会await返回值因此你可以在自定义清洗器中执行异步操作如查库转换 ID。标准清洗器如何进入链src/chain/sanitizers-impl.ts 中的addStandardSanitization负责把 validator.js 的函数包装成Sanitization项加入上下文构建器private addStandardSanitization(sanitizer: StandardSanitizer, ...options: any[]) { this.builder.addItem(new Sanitization(sanitizer, false, options)); return this.chain; }接口定义与实现分离接口声明在 src/chain/sanitizers.ts实现类在 src/chain/sanitizers-impl.ts并通过 src/chain/index.ts 统一对外导出最终合并进ValidationChain类型。综合实战一个完整的清洗链示例把以上知识组合成一个注册接口示例完整覆盖“清洗 → 校验 → 规范化”的典型链路import { body, param } from express-validator; app.post(/users, // 邮箱去空白 → 规范化全小写、去 Gmail 子地址→ 校验格式 body(email) .trim() .normalizeEmail({ all_lowercase: true, gmail_remove_subaddress: true }) .isEmail(), // 用户名去空白 → 若为空则给默认值 → 再校验长度 body(username) .trim() .default(anonymous) .isLength({ min: 3, max: 20 }), // 年龄转为整数 body(age).toInt(), // 是否接收订阅转为布尔 body(newsletter).toBoolean(), // 路径参数 ID按业务规则转换自定义清洗器 param(id).customSanitizer(value /^[0-9a-f]{24}$/.test(value) ? ObjectId(value) : Number(value)), (req, res) { // 此时 req.body.email/username/age/newsletter 均为清洗后的类型与值 res.json(req.body); }, );要点回顾清洗器按调用顺序依次执行依赖清洗结果的校验器要放在清洗器之后清洗结果会写回req.body/req.query/req.params下游可直接使用类型转换类清洗器toInt、toFloat、toBoolean、toDate能显著减少路由处理器内的手动Number()/parseInt()样板代码涉及安全场景时escape()、stripLow()只是基础手段输出到 HTML 前仍应使用专门的转义库。相关资源标准清洗器 API 清单docs/api/validator/_sanitizers.md标准校验器 API 清单docs/api/validator/_validators.md验证链完整 API含customSanitizer、default、replace、toArray等docs/api/validation-chain.md验证链概念与调用顺序指南docs/guides/validation-chain.md接口定义src/chain/sanitizers.ts实现源码src/chain/sanitizers-impl.ts底层执行机制src/context-items/sanitization.ts标准/自定义清洗器类型声明src/base.ts赞分享后端【免费下载链接】express-validatorAn express.js middleware for validator.js.项目地址https://gitcode.com/gh_mirrors/ex/express-validator点击查看免费下载相关推荐slime 评估数据集配置指南通过 --eval-config 与 --eval-prompt-data 添加周期评测数据slime 评估数据集配置指南通过 eval config 与 eval prompt data 添加周期评测数据 本篇指南围绕 slimeLLM 后训练后端为什么Codex-X是Codex用户必备神器7大核心亮点全解析为什么Codex X是Codex用户必备神器7大核心亮点全解析 Codex X 是一款面向 OpenAI Codex 桌面端 / Codex CLI 的跨平台后端express-validator 自定义校验器与净化器Custom Validators Sanitizers实战指南express validator 自定义校验器与净化器Custom Validators Sanitizers实战指南 express validat后端上一篇社区与支持GitHub_Trending/bi/biliTickerBuy用户交流群与问题反馈渠道汇总下一篇Groq Code CLI高级技巧代理配置与环境变量设置完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考