Koa 洋葱模型

Koa 中间件的执行机制和洋葱模型原理

问题

什么是 Koa 的洋葱模型?它是如何工作的?

解答

Koa 的洋葱模型是一种基于中间件的请求处理机制。请求像穿过洋葱一样,从外层中间件进入,到达核心后再从内向外返回。

执行流程

洋葱模型的执行分为两个阶段:

1. 请求阶段(外 → 内)

从第一个中间件开始,遇到 await next() 时进入下一个中间件,直到最后一个中间件执行完毕。

2. 响应阶段(内 → 外)

从最后一个中间件返回,依次执行每个中间件 await next() 之后的代码,最终返回响应。

代码示例

const Koa = require('koa');
const app = new Koa();

// 中间件 1
app.use(async (ctx, next) => {
  console.log('1 - 请求开始');
  await next();
  console.log('1 - 响应结束');
});

// 中间件 2
app.use(async (ctx, next) => {
  console.log('2 - 处理请求');
  await next();
  console.log('2 - 处理响应');
});

// 中间件 3
app.use(async (ctx, next) => {
  console.log('3 - 业务逻辑');
  ctx.body = 'Hello Koa';
});

app.listen(3000);

// 输出顺序:
// 1 - 请求开始
// 2 - 处理请求
// 3 - 业务逻辑
// 2 - 处理响应
// 1 - 响应结束

简化实现

function compose(middlewares) {
  return function (ctx) {
    function dispatch(i) {
      const middleware = middlewares[i];
      if (!middleware) return Promise.resolve();
      
      return Promise.resolve(
        middleware(ctx, () => dispatch(i + 1))
      );
    }
    return dispatch(0);
  };
}

关键点

  • 中间件通过 await next() 控制执行流程,之前的代码在请求阶段执行,之后的代码在响应阶段执行
  • 执行顺序是”先进后出”,类似栈结构,形成洋葱状的层层包裹
  • 每个中间件可以修改 ctx 对象,影响后续中间件和最终响应
  • 错误处理中间件应放在最外层,可以捕获内层中间件的异常
  • 必须调用 await next() 才能将控制权传递给下一个中间件,否则会中断执行链