← 返回文章列表
Node.js·782 次阅读

Koa 洋葱模型与 async 中间件

Koa 洋葱模型与 async 中间件

Koa 是 Express 原班团队打造的下一代框架,体积更小、没有内置任何中间件,核心机制就是著名的洋葱模型。

什么是洋葱模型

中间件的执行像穿过洋葱:请求从外层进入,逐层向内;next() 之后的代码在响应回程中从内向外执行:

app.use(async (ctx, next) => {
  console.log('1 进入')
  await next() // 交给内层,内层全部完成后才继续
  console.log('1 出去')
})

app.use(async (ctx, next) => {
  console.log('2 进入')
  await next()
  console.log('2 出去')
})
// 输出:1 进入 → 2 进入 → 2 出去 → 1 出去

Express 也有 next,但因为回调时代没有强制 await,"回程逻辑"写起来很别扭。Koa 的中间件全是 async 函数,await next() 让"前后环绕"成为天然结构——日志计时、异常捕获、事务包裹都极其优雅:

// 统一错误处理:一个外层中间件兜住所有内层异常
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = err.statusCode || 500
    ctx.body = { message: err.message }
  }
})

// 耗时统计
app.use(async (ctx, next) => {
  const start = Date.now()
  await next()
  ctx.set('X-Response-Time', Date.now() - start + 'ms')
})

ctx 上下文

Express 是 req/res 两个对象,Koa 合并为一个 ctx,并封装了常用属性:ctx.request/ctx.response、ctx.query、ctx.params、ctx.body(直接赋对象,自动 JSON 序列化)、ctx.status。

手写核心 compose

洋葱模型的实现核心是把中间件数组组合成一条嵌套调用链:

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

关键:next 就是 () => dispatch(i+1),async 函数 await 它时,后面所有中间件都被 await,回程顺序自然形成。

Express 还是 Koa

  • 生态丰富、上手快、传统 MVC → Express
  • async 体验、干净的中间件模型、需要自己掌控架构 → Koa(Egg.js 等上层框架也基于它)

理解了 compose,这一类中间件框架(甚至 h3/Nitro)在你眼里就都透明了。

看到这里了?如果这篇文章帮到过你

请我喝瓶可乐就好 🥤

收款码

评论0 条

还没有评论,来抢沙发~

发表评论

评论需审核后显示

© 2026 许冬博客 · 专注 JS 技术分享

·RSS 订阅·Powered by Nuxt 4