目录
[1. 基础结构:自定义中间件原理](#1. 基础结构:自定义中间件原理)
[2. 实战示例:手动编写验证中间件](#2. 实战示例:手动编写验证中间件)
[3. 进阶方式:使用 express-validator 库](#3. 进阶方式:使用 express-validator 库)
[4. 高级技巧:可复用的验证工厂](#4. 高级技巧:可复用的验证工厂)
[✔ 最佳实践总结 ✔](#✔ 最佳实践总结 ✔)


在 Express.js 中创建自定义验证中间件,核心在于编写一个能够访问**req(请求对象)、res**(响应对象)和 next(下一个中间件函数)的函数。该函数负责检查请求数据,若验证失败则直接终止请求并返回错误,若验证通过则调用 next() 将控制权交给后续处理逻辑。
以下是创建和使用自定义验证中间件的完整指南:
1. 基础结构:自定义中间件原理
Express 中间件是一个标准的 JavaScript 函数,其签名如下:
javascript
function middlewareName(req, res, next) {
// 1. 执行验证逻辑
// 2. 如果验证失败:res.status(400).json({ error: '...' })
// 3. 如果验证成功:next()
}
**关键点:**
- 必须调用
next():如果验证通过,必须调用next(),否则请求会挂起,客户端收不到响应。 - 提前终止 :如果验证失败,发送响应后不要 调用
next(),以防止执行后续的业务逻辑。
2. 实战示例:手动编写验证中间件
假设我们需要验证用户注册接口,确保 username 和**email**字段存在且格式正确。
步骤一:定义验证中间件
你可以创建一个独立的函数或模块来封装验证逻辑。
javascript
// 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;
步骤二:在路由中使用
将中间件挂载到特定的路由上。注意中间件函数的顺序:验证中间件必须在业务逻辑处理函数之前。
javascript
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,提供了链式调用的验证规则和数据净化功能。
**安装:**
bash
npm install express-validator
**实现代码:**
javascript
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. 高级技巧:可复用的验证工厂
为了进一步提高代码复用性,可以创建一个"工厂函数"来生成针对特定字段的验证中间件。
javascript
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 应用免受无效或恶意数据的侵害。
☑ 相关参考 ☑
Nodejs | 深入理解Express框架之如何使用各类中间件
