Express.js中express-validator的validationResult中间件失效问题
Express-validator 全局中间件无法获取校验错误的解决办法
问题现象
在Express.js项目中使用express-validator做参数校验时,出现了如下矛盾现象:
- 控制器中调用
validationResult(req)能正常返回错误信息,errors.isEmpty()返回false - 全局校验中间件中调用
validationResult(req)时,errors.isEmpty()却返回true,完全获取不到任何错误信息
相关代码如下:
index文件
app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) app.use(validatorMiddleware) // 全局注册校验中间件 app.use(router)
校验中间件
const validatorMiddleware = (req: Request, res: Response, next: NextFunction) => { const errors = validationResult(req) console.log(errors.isEmpty()) // 这里总是输出true if (errors.isEmpty()) { return next() } return res.status(422).json({ errors: errors, }) }
路由文件
const router = Router() router.post('/register', registerRequest(), authController.register); export default router
registerRequest校验规则
const registerRequest = () => [ body('username').notEmpty().withMessage('Username is required'), body('email').isEmail().withMessage('Invalid email address'), body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters long') ]
问题原因
核心问题是中间件执行顺序错误:
- 你将
validatorMiddleware作为全局中间件注册在router之前,意味着请求进来会先执行这个全局中间件 - 路由里的
registerRequest()返回的校验规则中间件,属于路由处理链的一部分,只会在路由匹配成功后才执行 - 因此
validatorMiddleware执行时,参数校验逻辑还未运行,自然收集不到错误,errors.isEmpty()返回true - 而控制器
authController.register在registerRequest()的校验中间件之后执行,此时校验已完成,能正常拿到错误信息
解决方案
把validatorMiddleware从全局中间件中移除,改为放到路由的处理链里,让它在校验规则中间件之后执行:
修改后的路由文件
const router = Router() // 执行顺序:校验规则中间件 -> 错误处理中间件 -> 控制器 router.post('/register', registerRequest(), validatorMiddleware, authController.register); export default router
修改后的index文件
app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) // 移除全局的validatorMiddleware注册 app.use(router)
调整后,请求会先执行registerRequest()的校验逻辑收集错误,再执行validatorMiddleware,就能正确捕获校验错误并返回。
如果有多个路由需要校验,可以封装一个通用校验函数减少重复代码:
const validate = (validations) => { return async (req, res, next) => { await Promise.all(validations.map(validation => validation.run(req))); const errors = validationResult(req); if (errors.isEmpty()) { return next(); } res.status(422).json({ errors: errors.array() }); }; }
路由中可简化为:
router.post('/register', validate(registerRequest()), authController.register);
内容的提问来源于stack exchange,提问作者Pooria Sadeghy
相关产品推荐
相关产品推荐

