侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现一个简单的中间件系统并解释洋葱模型

2025-12-7 / 0 评论 / 4 阅读

题目

实现一个简单的中间件系统并解释洋葱模型

信息

  • 类型:问答
  • 难度:⭐⭐

考点

中间件原理, 洋葱模型, 异步流程控制

快速回答

实现要点:

  • 创建上下文对象(context)存储请求/响应数据
  • 使用数组存储中间件函数
  • 通过递归组合实现中间件链式执行
  • 每个中间件接收 contextnext 参数

洋葱模型特点:

  • 请求顺序:中间件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 编程:面向切面编程在中间件中的应用