Express中间件开发实战:从0到1构建可复用的Web插件
你还在为重复编写验证逻辑而烦恼?还在纠结如何优雅地扩展Express功能?本文将带你掌握自定义中间件的完整开发流程,从基础结构到NPM发布,用150行代码打造生产级中间件,让你的Express应用更灵活、更高效。
中间件核心概念
Express中间件(Middleware)是一种拦截HTTP请求的函数,能够在请求到达路由处理前执行特定逻辑。它就像流水线工人,依次对请求进行加工处理。典型应用场景包括:
- 请求日志记录
- 用户身份验证
- 跨域资源共享(CORS)处理
- 错误捕获与处理
项目中benchmarks/middleware.js展示了基础中间件结构:
app.use(function(req, res, next){
// 中间件逻辑
next(); // 传递给下一个中间件
});
从零编写中间件
基础结构模板
所有Express中间件都遵循相同的函数签名,接受三个参数:
req:请求对象(Request)res:响应对象(Response)next:回调函数,调用后将控制权交给下一个中间件
// 基础中间件模板
function myMiddleware(req, res, next) {
// 1. 处理请求逻辑
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
// 2. 调用next()传递控制权
next();
// 注意:next()之后的代码仍会执行
// 适合记录响应时间等后置操作
}
// 应用中间件
app.use(myMiddleware);
带配置参数的中间件
当需要自定义中间件行为时,可通过高阶函数实现参数传递:
// 带配置的日志中间件
function logger(options = {}) {
const { level = 'info' } = options;
return function(req, res, next) {
const start = Date.now();
// 记录请求信息
console.log(`[${level}] ${req.method} ${req.url}`);
// 监听响应完成事件
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${level}] ${res.statusCode} ${duration}ms`);
});
next();
};
}
// 使用带参数的中间件
app.use(logger({ level: 'debug' }));
路由级中间件
中间件可精准应用于特定路由,实现细粒度控制。examples/route-middleware/index.js展示了路由中间件的典型应用:
// 用户加载中间件
function loadUser(req, res, next) {
const user = users[req.params.id];
if (user) {
req.user = user; // 将数据附加到请求对象
next(); // 继续处理
} else {
next(new Error('用户不存在')); // 传递错误
}
}
// 权限控制中间件
function checkPermission(req, res, next) {
if (req.authenticatedUser.id === req.user.id) {
next();
} else {
next(new Error('无权限访问'));
}
}
// 应用于特定路由
app.get('/user/:id/edit', loadUser, checkPermission, (req, res) => {
res.send(`编辑用户: ${req.user.name}`);
});
常用中间件模式
异步处理中间件
对于数据库查询等异步操作,需使用异步函数:
// 异步用户验证中间件
async function asyncAuth(req, res, next) {
try {
const user = await UserModel.findById(req.cookies.userId);
if (user) {
req.user = user;
next();
} else {
next(new Error('未授权'));
}
} catch (err) {
next(err); // 传递错误给错误处理中间件
}
}
错误处理中间件
错误处理中间件需要四个参数,专门捕获流程中的异常:
// 集中式错误处理
app.use(function(err, req, res, next) {
console.error(err.stack);
// 根据错误类型返回不同响应
if (err.message === '未授权') {
return res.status(401).send('请先登录');
}
// 默认500错误
res.status(500).send('服务器内部错误');
});
测试与调试
本地测试方法
创建examples/route-middleware/index.js测试文件:
const express = require('express');
const app = express();
const myMiddleware = require('./my-middleware');
// 应用自定义中间件
app.use(myMiddleware());
app.get('/', (req, res) => {
res.send('Hello World');
});
// 错误处理
app.use((err, req, res, next) => {
res.status(500).send(err.message);
});
app.listen(3000, () => {
console.log('服务器运行于3000端口');
});
使用curl测试:
curl http://localhost:3000
curl http://localhost:3000/user/1/edit
单元测试
使用Mocha和Chai编写单元测试:
const { expect } = require('chai');
const httpMocks = require('node-mocks-http');
const myMiddleware = require('../lib/my-middleware');
describe('My Middleware', () => {
it('should add timestamp to request', () => {
const req = httpMocks.createRequest();
const res = httpMocks.createResponse();
const next = () => {};
myMiddleware()(req, res, next);
expect(req.timestamp).to.be.a('number');
});
});
发布到NPM
项目结构
my-middleware/
├── index.js # 中间件主文件
├── package.json # 包配置
├── README.md # 使用文档
└── test/ # 测试目录
└── index.test.js # 测试文件
package.json配置
{
"name": "express-my-middleware",
"version": "1.0.0",
"description": "Express日志中间件",
"main": "index.js",
"keywords": ["express", "middleware", "logger"],
"author": "Your Name",
"license": "MIT",
"peerDependencies": {
"express": ">=4.0.0"
},
"devDependencies": {
"mocha": "^9.0.0",
"chai": "^4.3.4"
},
"scripts": {
"test": "mocha"
}
}
发布命令
# 登录NPM
npm login
# 发布包
npm publish
# 更新版本
npm version patch
npm publish
实战案例:请求限流中间件
下面实现一个防止API滥用的限流中间件:
const rateLimit = require('express-rate-limit');
// 应用限流中间件
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个IP限制100请求
standardHeaders: true,
legacyHeaders: false,
message: '请求过于频繁,请稍后再试'
});
// 应用到API路由
app.use('/api/', apiLimiter);
完整代码可参考examples/rate-limit/index.js实现。
最佳实践
- 单一职责:每个中间件只做一件事
- 尽早返回:错误处理优先
- 文档完善:说明参数、副作用和使用场景
- 向后兼容:支持Express不同版本
- 性能考量:避免同步阻塞操作
总结与展望
通过本文学习,你已掌握Express中间件的开发全过程。中间件机制是Express灵活性的核心,合理使用能极大提升代码复用率。建议深入研究项目中examples/目录下的auth、cookies等官方示例,进一步掌握高级用法。
下一篇我们将探讨中间件的高级模式,包括洋葱模型原理和异步错误处理,敬请期待!
如果你觉得本文有帮助,请点赞收藏,关注获取更多Express实战教程。如有疑问,欢迎在评论区留言讨论。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



