news 2026/10/10 8:43:43

express-validator 入门实战:用 Express 中间件完成请求参数校验与错误报告

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
express-validator 入门实战:用 Express 中间件完成请求参数校验与错误报告
  • 后端

【免费下载链接】express-validator

An express.js middleware for validator.js.

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

express-validator 是一组面向 Express 的中间件集合,它在 validator.js 提供的校验器(validator)与净化器(sanitizer)之上,为你的路由添加声明式的字段校验能力。本文将以 5.2.0 版本文档的 Getting Started 指南为主体,结合仓库源码带你从安装起步,一步步把一段不设防的 Express 路由改造成带check()校验链与validationResult()错误收集的完整示例,并理解校验链底层如何串行执行、错误对象如何结构化输出,为后续进阶功能(净化、自定义校验器、自定义错误消息、通配符、Schema 校验)打下基础。

express-validator 是什么

express-validator 本质上是一个薄封装层:它把 validator.js 的校验与净化函数包装成Express 中间件(Middleware),让你能够像声明路由一样声明"某个字段必须满足哪些规则"。官方对其定位的描述是:

express-validator is a set of express.js middlewares that wraps validator.js validator and sanitizer functions.

在阅读本指南前,官方文档建议你先具备 express.js 模块的基础知识(中间件、路由、req/res的基本用法),因为校验中间件需要嵌入到 Express 的路由处理流程中才能发挥作用。

当前仓库即 express-validator 的完整源码工程(package.json 中版本号为 7.3.2),核心实现位于src/目录,通过 TypeScript 编写并编译输出到lib/。本文讲解的入门流程在 5.2.0 及后续版本中一脉相承:check()构建校验链、校验链作为中间件挂载、validationResult()汇总错误。

安装与运行环境

使用 npm 安装即可(5.2.0 文档要求 Node.js 6 或更新版本):

npm install --save express-validator

需要说明的是,随着项目演进,当前仓库 package.json 的engines字段已要求node >= 14.0.0,并且依赖了validator ~13.x与lodash。如果你使用较新的 Node 版本,直接npm install express-validator后即可开始下面的示例。安装完成后,项目会同时提供编译产物与类型声明(main: ./lib/index.js、types: ./lib/index.d.ts),TypeScript 用户开箱即用。

基础指南:从无校验路由到带校验路由

第一步:先写一个不设防的路由

入门示例从"创建用户"接口开始。下面的路由直接读取req.body并落库,完全没有对输入做任何检查:

const express = require('express'); const app = express(); app.use(express.json()); app.post('/user', (req, res) => { User.create({ username: req.body.username, password: req.body.password }).then(user => res.json(user)); });

这段代码的问题很明显:username可以是任意内容,password可以是任意长度,任何畸形请求都会直接进入数据库逻辑。接下来我们引入 express-validator 来补上这道防线。

第二步:用 check() 声明校验规则

导入check与validationResult(5.2.0 时代从express-validator/check子模块导入;当前仓库版本则统一从express-validator根入口导入,src/index.ts会导出check、body、validationResult等全部 API):

// ...rest of the initial code omitted for simplicity. const { check, validationResult } = require('express-validator/check'); app.post('/user', [ // username must be an email check('username').isEmail(), // password must be at least 5 chars long check('password').isLength({ min: 5 }) ], (req, res) => { // Finds the validation errors in this request and wraps them in an object with handy functions const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } User.create({ username: req.body.username, password: req.body.password }).then(user => res.json(user)); });

这里发生了什么:

  1. check('username').isEmail()创建了一条针对username字段的校验链(Validation Chain),并追加了isEmail()校验规则;
  2. check('password').isLength({ min: 5 })同样为password创建校验链,要求长度至少为 5;
  3. 两条校验链组成数组作为中间件数组传给app.post('/user', ...),在进入业务处理函数之前被执行;
  4. 业务处理函数中通过validationResult(req)取出本次请求的所有校验错误,errors.isEmpty()判断是否通过,不通过则返回 HTTP 400 与错误数组。

从源码看,check()的实现位于 src/middlewares/check.ts:它用ContextBuilder记录字段名、请求位置与默认消息,构建ContextRunnerImpl运行器,再通过Object.assign把运行器、校验器(ValidatorsImpl)、净化器(SanitizersImpl)与上下文处理方法绑定到同一个中间件函数上——这就是为什么一条校验链既能当中间件使用,又能链式调用.isEmail()、.isLength()、.trim()等方法的原因。测试 src/middlewares/check.spec.ts 也验证了校验链同时具备 validator、sanitizer、context-handler 与 context-runner 四类方法。

第三步:看看校验失败时的响应

Voila!现在,任何包含非法username或password字段的请求都会被拦截,服务器会返回如下结构的 JSON:

{ "errors": [{ "location": "body", "msg": "Invalid value", "param": "username" }] }

这个错误对象是"字段级校验错误"的经典结构,含义为:

  • location:出错字段所在的请求位置,这里是body(还可能是cookies、headers、params、query);
  • msg:错误消息。当某条校验规则没有显式指定消息时,默认就是Invalid value;
  • param:出错的字段名。

对照当前仓库 src/base.ts 中定义的FieldValidationError类型可以看到,这一结构在后续版本中被细化为type: 'field'+location+path+value+msg的联合类型(字段名param演化为path),并且错误类型扩展出了alternative(oneOf()全部备选失败)、unknown_fields(checkExact()发现未知字段)等种类。但入门阶段你只需要理解:每个校验错误都携带"位置 + 字段 + 消息"三元信息,足够客户端精确提示。

第四步:校验通过后的正常流程

当username与password都合法时,validationResult(req).isEmpty()返回true,代码继续执行原有的User.create(...)逻辑,整个流程与最初的版本完全一致——express-validator 只在请求进入业务逻辑之前"拦截"非法输入,不改变合法的业务行为。

check() 校验链的工作原理(源码视角)

入门示例里最核心的 API 是check()。虽然入门指南只展示了最简用法,但理解其机制有助于你写出正确的校验代码。

校验的五个请求位置

check()默认会在以下所有请求对象中查找目标字段(从 src/middlewares/validation-chain-builders.ts 可见其默认 locations 为['body', 'cookies', 'headers', 'params', 'query']):

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

如果某个字段在多个位置同时出现,那么每一处取值都必须通过校验。例如请求同时携带query.id与body.id,check('id')会对两处值分别校验。

定位字段:通配符与路径展开

字段选择逻辑在 src/field-selection.ts 中实现:selectFields会把"字段 × 位置"展开成一组FieldInstance(含location、path、value),并自动去重。它还支持*、**通配符用于嵌套对象与数组(例如check('products.*.price')),这是入门后进阶(Wildcards 特性)的地基。另外注意:对于headers位置,字段名会被统一转为小写后再匹配。

校验链的执行顺序

check()构建出的校验链在作为中间件执行时,内部由 src/chain/context-runner-impl.ts 的run()驱动,关键行为包括:

  • 同一字段的校验规则串行执行:校验链上的.isEmail()、.isLength()等规则按声明顺序逐个运行,后一个规则看到的是前一个规则运行后的值(净化器修改值后,后续校验基于新值);
  • 不同字段并行执行:如果一条校验链同时覆盖多个字段,这些字段的校验互不阻塞;
  • 值回写:净化器(sanitizer)修改字段值后,运行器会把新值写回req对应位置(_.set(req[location], path, newValue)),这就是.trim()等净化方法能"原地修正输入"的原理;
  • 上下文收集:每个中间件运行后,其校验上下文(含错误列表)被挂到请求的express-validator#contexts键上(见 src/base.ts 的contextsKey),validationResult(req)正是从这里汇总所有中间件的错误。

字段缺省时的行为

入门示例只展示了普通字段校验。若调用check()时不传任何字段,则校验整个请求位置(通常仅对req.body有意义,即 Whole Body Validation 特性)。本指南不展开,详见后续的进阶文档。

validationResult:统一收集与读取校验错误

validationResult(req)接收 Express 的请求对象,把所有中间件产生的校验错误抽取出来,包装成一个validation result 对象。其实现位于 src/validation-result.ts,核心逻辑是:从请求的 contexts 中flatMap出所有错误,交给Result类实例管理。

Result实例提供了几个实用的方法:

  • isEmpty():是否没有错误,入门示例用它作为继续执行业务逻辑的开关;
  • array():把错误转换为数组(默认返回全部错误;传入{ onlyFirstError: true }则每个字段只保留第一条错误),入门示例用errors.array()直接序列化进响应;
  • mapped():把错误转换为"字段名 → 错误"的对象形式,便于按字段快速取用;
  • throw():若存在校验错误则直接抛出异常,适合在try/catch中配合统一错误处理中间件使用;
  • formatWith(fn):返回一个使用自定义格式化函数的新Result实例,用于定制错误输出结构。

入门示例中的res.status(400).json({ errors: errors.array() })即为最典型的用法:isEmpty()判断 +array()输出。

校验规则从哪里来

示例中的isEmail()、isLength({ min: 5 })并非 express-validator 自己实现,而是直接来自 validator.js 的校验器集合。express-validator 把 validator.js 中所有可用的校验器(及其选项)以同名方法的形式暴露在校验链上。当你需要更多内置规则(如isInt、isUUID、isIn等)时,可直接在链式调用中查阅这些方法及其选项。仓库的 declarations/validator.d.ts 即为 validator.js 的类型声明,可作为方法清单参考。

接下来可以深入的方向

入门指南到此已经覆盖了"安装 → 声明校验 → 收集错误 → 返回 400"的完整闭环。官方文档在此基础上推荐了五个进阶方向,均可在本仓库website/versioned_docs/version-5.2.0/目录下找到对应文档:

  • Sanitization(净化):使用.trim()、.escape()等方法在写入数据库前清理输入,防止脏数据与 XSS;
  • Custom validators/sanitizers(自定义校验器与净化器):当内置规则不够用时,编写自己的校验逻辑;
  • Custom error messages(自定义错误消息):把默认的Invalid value替换为对用户友好的提示;
  • Wildcards(通配符):校验嵌套对象与数组中的字段;
  • Schema validation(Schema 校验):用声明式 Schema 对象一次性描述整张表单的校验规则。

在开始这些进阶话题之前,建议你先亲手把上面的/user路由跑通:发起一个带非法username或过短password的 POST 请求,观察 400 响应中的errors数组结构;再通过合法请求确认User.create正常执行。一旦你掌握了"校验链 + validationResult"这对组合,express-validator 的其余特性都只是在这条主线上叠加更多规则与更灵活的错误处理而已。

  • 后端

【免费下载链接】express-validator

An express.js middleware for validator.js.

项目地址:https://gitcode.com/gh_mirrors/ex/express-validator
点击查看免费下载
上一篇:BilibiliDown终极指南:3步轻松下载B站高清视频与音频
下一篇:中国行政区划数据标准化难题与五级联动数据架构解决方案

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

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

用C++实现三国杀:回合状态机与事件驱动设计

简介:C实现的《三国杀》纸牌游戏完整工程,适合C初学者、课程设计或游戏开发入门的读者。资源包含可直接编译运行的源代码文件和配套设计报告文档,共2个文件,压缩包约1.21MB。代码覆盖随机发牌、牌面比较、输赢统计与结果输出&…

作者头像 李华
网站建设 2026/10/10 8:41:46

10 分钟给 Windows 11 减重提速:Win11Debloat 系统优化新手指南

10 分钟给 Windows 11 减重提速:Win11Debloat 系统优化新手指南 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutt…

作者头像 李华
网站建设 2026/10/10 8:41:04

告别JSONP与XML测试噩梦:jQuery Mockjax多数据类型Mock完整指南

告别JSONP与XML测试噩梦:jQuery Mockjax多数据类型Mock完整指南 【免费下载链接】jquery-mockjax The jQuery Mockjax Plugin provides a simple and extremely flexible interface for mocking or simulating ajax requests and responses 项目地址: https://git…

作者头像 李华
网站建设 2026/10/10 8:38:33

西门子S7-1200恒压供水一拖三控制:从PID调节到接触器互锁实战

接手这套项目的时候,业主反复问过一句话:“三台泵为什么不能一起变频?既然有变频器,直接一台变频器拖三台电机,不是更省事?”——做过楼宇供水改造的朋友,大概率都听过类似的问题。答案其实不复…

作者头像 李华
网站建设 2026/10/10 8:38:31

使用双指针解决链表题

这是一篇初出茅庐的小白被链表题整疯后对双指针解决链表题的见解。双指针,即使用两个指针去解决问题。能用两个指针解决的问题通常用一个指针也能解决,但是双指针相比于单指针,在时间复杂度和空间复杂度方面都占优势。(来源:LeetC…

作者头像 李华
网站建设 2026/10/10 8:37:13

基于微信小程序的校园运动搭子平台设计与实现-附源码

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华