Node| 如何创建一个自定义的验证中间件?
目录
1. 基础结构:自定义中间件原理
2. 实战示例:手动编写验证中间件
步骤一:定义验证中间件
步骤二:在路由中使用
3. 进阶方式:使用 express-validator 库
4. 高级技巧:可复用的验证工厂
✔ 最佳实践总结 ✔
在 Express.js 中创建自定义验证中间件,核心在于编写一个能够访问req(请求对象)、res(响应对象)和next(下一个中间件函数)的函数。该函数负责检查请求数据,若验证失败则直接终止请求并返回错误,若验证通过则调用next()将控制权交给后续处理逻辑。
以下是创建和使用自定义验证中间件的完整指南:
1. 基础结构:自定义中间件原理
Express 中间件是一个标准的 JavaScript 函数,其签名如下:
function middlewareName(req, res, next) { // 1. 执行验证逻辑 // 2. 如果验证失败:res.status(400).json({ error: '...' }) // 3. 如果验证成功:next() }关键点:
- 必须调用
next():如果验证通过,必须调用next(),否则请求会挂起,客户端收不到响应。 - 提前终止:如果验证失败,发送响应后不要调用
next(),以防止执行后续的业务逻辑。
2. 实战示例:手动编写验证中间件
假设我们需要验证用户注册接口,确保username和email字段存在且格式正确。
步骤一:定义验证中间件
你可以创建一个独立的函数或模块来封装验证逻辑。
// middleware/validateUser.js const validateUser = (req, res, next) => { const { username, email } = req.body; const errors = []; // 验证用户名 if (!username || typeof username !== 'string' || username.trim().length < 3) { errors.push('Username is required and must be at least 3 characters long'); } // 验证邮箱格式 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!email || !emailRegex.test(email)) { errors.push('Valid email address is required'); } // 如果有错误,返回 400 状态码并停止后续执行 if (errors.length > 0) { return res.status(400).json({ status: 'error', message: 'Validation failed', details: errors }); } // 验证通过,继续执行下一个中间件或路由处理器 next(); }; module.exports = validateUser;步骤二:在路由中使用
将中间件挂载到特定的路由上。注意中间件函数的顺序:验证中间件必须在业务逻辑处理函数之前。
const express = require('express'); const app = express(); const validateUser = require('./middleware/validateUser'); // 解析 JSON 请求体 app.use(express.json()); // POST /register 路由 // 顺序:1. parse JSON -> 2. validateUser -> 3. handler app.post('/register', validateUser, (req, res) => { // 此时可以确信 req.body.username 和 req.body.email 是有效的 const { username, email } = req.body; // 模拟数据库操作 console.log(`Creating user: ${username}, ${email}`); res.status(201).json({ status: 'success', message: 'User registered successfully', data: { username, email } }); }); app.listen(3000, () => console.log('Server running on port 3000'));3. 进阶方式:使用express-validator库
对于复杂项目,手动编写正则表达式和条件判断容易出错且难以维护。推荐使用业界标准的express-validator库,它基于validator.js,提供了链式调用的验证规则和数据净化功能。
安装:
npm install express-validator实现代码:
const { body, validationResult } = require('express-validator'); const express = require('express'); const app = express(); app.use(express.json()); // 定义验证规则数组 const registerValidationRules = [ body('username') .trim() .notEmpty().withMessage('Username is required') .isLength({ min: 3 }).withMessage('Username must be at least 3 characters'), body('email') .normalizeEmail() .isEmail().withMessage('Invalid email format'), body('password') .isLength({ min: 8 }).withMessage('Password must be at least 8 characters') .matches(/[0-9]/).withMessage('Password must contain a number') ]; // 通用错误处理中间件(可选,用于统一处理验证结果) const handleValidationErrors = (req, res, next) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } next(); }; // 应用验证规则 app.post('/register', registerValidationRules, // 1. 执行验证规则 handleValidationErrors, // 2. 检查验证结果 (req, res) => { // 3. 业务逻辑 res.json({ message: 'User created', data: req.body }); } ); app.listen(3000);4. 高级技巧:可复用的验证工厂
为了进一步提高代码复用性,可以创建一个“工厂函数”来生成针对特定字段的验证中间件。
const { body, validationResult } = require('express-validator'); // 创建一个通用的验证中间件生成器 const createValidator = (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(400).json({ errors: errors.array() }); }; }; // 定义具体的验证规则 const userRegistrationValidations = [ body('email').isEmail(), body('password').isLength({ min: 6 }) ]; // 生成中间件 const validateRegistration = createValidator(userRegistrationValidations); // 使用 app.post('/signup', validateRegistration, (req, res) => { res.send('Signup successful'); });✔ 最佳实践总结 ✔
- 分离关注点:验证中间件只负责数据格式和完整性检查,不应包含数据库查询或业务逻辑(如“用户是否已存在”属于业务逻辑,但“邮箱格式是否正确”属于验证)。
- 统一错误格式:确保所有验证失败的响应具有相同的 JSON 结构,便于前端统一处理。
- 数据净化:在验证的同时进行数据清洗(如
trim()去除空格,escape()防止 XSS),express-validator内置了这些功能。 - 异步支持:如果验证需要查询数据库(如检查用户名唯一性),中间件函数应声明为
async,并使用await等待异步操作完成。 - 位置安排:确保验证中间件位于
express.json()之后,以便能访问到解析后的req.body。
通过上述方法,你可以构建出既安全又易于维护的请求验证层,有效保护你的 Express 应用免受无效或恶意数据的侵害。
☑ 相关参考 ☑
Node | 如何在Express.js中处理异步验证逻辑
Nodejs | 深入理解Express框架之如何使用各类中间件
