如何将req.params作为参数传递给Express中间件函数?
解决Express中根据路由参数动态加载express-validator校验规则的问题
这问题我之前踩过坑!你说的完全对——原来的代码没法运行,是因为路由定义代码是在服务器启动时执行的,这时候req对象还没被创建,自然访问不到req.params。想要实现动态加载校验规则,核心是把校验逻辑放到请求到达时才会执行的中间件函数内部。
这里有两种简单可行的方案:
方案一:封装一个动态校验中间件函数
先写一个包装函数,它会返回一个能访问req的中间件,在中间件里根据路由参数获取对应的校验 schema,再调用checkSchema执行校验:
const { checkSchema, validationResult } = require('express-validator'); // 封装动态校验中间件的工厂函数 const getDynamicSchemaValidator = () => { return (req, res, next) => { const schemaKey = req.params.myParam; // 先做个兜底,避免传入不存在的schema导致报错 if (!schemas[schemaKey]) { return res.status(400).json({ error: '无效的参数类型,请检查路由参数' }); } // 调用checkSchema生成校验链,并执行校验 checkSchema(schemas[schemaKey])(req, res, (err) => { if (err) return next(err); // 手动校验结果,也可以留到后面用validationResult统一处理 const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } next(); }); }; }; // 路由中使用 router.post('/:myParam', getDynamicSchemaValidator(), async (req, res, next) => { // 这里已经通过校验,放心处理业务逻辑 // do stuff });
方案二:直接在路由中使用匿名中间件
如果不想单独封装函数,也可以直接在路由里加一个匿名中间件来处理动态schema的逻辑,写法更简洁:
const { checkSchema, validationResult } = require('express-validator'); router.post('/:myParam', // 第一个中间件:动态获取schema并执行校验 (req, res, next) => { const targetSchema = schemas[req.params.myParam]; if (!targetSchema) { return res.status(400).send('无效的路由参数,找不到对应的校验规则'); } // 调用checkSchema并传递req/res/next checkSchema(targetSchema)(req, res, next); }, // 第二个中间件:校验通过后的业务逻辑 async (req, res, next) => { // 先检查校验结果(如果前面没手动处理的话) const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } // do stuff } );
核心原理说明
路由定义代码是服务器启动阶段同步执行的,这时候还没有任何请求进来,req对象根本不存在;而中间件函数是当请求到达时才会被调用的,这时候req已经被Express创建好,就能正常访问req.params了。所以只要把动态获取schema的逻辑放到中间件内部,就能解决作用域的问题。
内容的提问来源于stack exchange,提问作者Glenn
相关产品推荐
相关产品推荐

