题目
实现一个简单的中间件系统并解释洋葱模型
信息
- 类型:问答
- 难度:⭐⭐
考点
中间件原理, 洋葱模型, 异步流程控制
快速回答
实现要点:
- 创建上下文对象(context)存储请求/响应数据
- 使用数组存储中间件函数
- 通过递归组合实现中间件链式执行
- 每个中间件接收
context和next参数
洋葱模型特点:
- 请求顺序:中间件1 → 中间件2 → ... → 核心逻辑
- 响应逆序:核心逻辑 → ... → 中间件2 → 中间件1
1. 中间件核心原理
中间件本质是函数队列的链式调用,核心是:
- 组合模式:将多个独立处理单元组合成处理管道
- 上下文传递:共享的 context 对象贯穿整个生命周期
- 控制反转:通过 next() 将执行权交给下一个中间件
2. 代码实现示例
class MiddlewareSystem {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
}
execute(context) {
const dispatch = (i) => {
if (i >= this.middlewares.length) return Promise.resolve();
const middleware = this.middlewares[i];
// 关键:next 是下一个中间件的封装
return middleware(context, () => dispatch(i + 1));
};
return dispatch(0);
}
}
// 使用示例
const app = new MiddlewareSystem();
app.use(async (ctx, next) => {
console.log('Middleware 1 start');
ctx.data = 'initial';
await next(); // 执行权移交
console.log('Middleware 1 end', ctx.data);
});
app.use(async (ctx, next) => {
console.log('Middleware 2 start');
ctx.data += ' → processed';
await next();
ctx.data += ' → finalized';
console.log('Middleware 2 end');
});
(async () => {
const ctx = { data: '' };
await app.execute(ctx);
// 输出顺序:
// Middleware 1 start
// Middleware 2 start
// Middleware 2 end
// Middleware 1 end 'initial → processed → finalized'
})();3. 洋葱模型解析

- 请求阶段:从外到内依次执行中间件的前置逻辑
- 响应阶段:从内到外依次执行中间件的后置逻辑
- 核心机制:通过 next() 实现执行权转移,类似递归调用
4. 最佳实践
- 错误处理:在最外层添加 catch 中间件
- 异步支持:始终返回 Promise 确保异步兼容
- 性能优化:避免在中间件中进行阻塞操作
- 上下文设计:冻结关键属性防止意外修改
5. 常见错误
- 忘记调用 next():导致后续中间件无法执行
- 多次调用 next():引发执行顺序混乱
- 修改 context 原型:造成全局污染
- 同步中使用异步 next:未 await next() 导致后置逻辑错乱
6. 扩展知识
- Koa 的实现:通过 compose 函数组合中间件
- Express 差异:基于回调而非 Promise,无内置洋葱后置处理
- 拦截器模式:类似 Axios 的请求/响应拦截器
- AOP 编程:面向切面编程在中间件中的应用