跳转到内容

洋葱模型

什么是洋葱模型?

洋葱模型是一种中间件架构模式,得名于其执行过程像剥洋葱一样层层深入再层层返回的特点。它广泛应用于 Node.js 的 Web 框架中,如 Koa.js

特点:

  1. 双向执行流程

    • 请求阶段:从外层中间件向内层执行
    • 响应阶段:从内层中间件向外层返回
  2. 控制权传递

    • 每个中间件通过 next() 函数将控制权传递给下一个中间件
    • 只有当后续中间件执行完毕后,才会回到当前中间件继续执行剩余代码
  3. 错误处理

    • 可以在任意中间件捕获后续中间件抛出的错误
    • 提供统一的错误处理机制

基础版

ts
export type Next = () => Promise<void>
export type Middleware<T> = (context: T, next: Next) => Promise<void>

export class OnionModel<T = any> {
  private middlewares: Middleware<T>[] = []

  // 添加中间件
  use(middleware: Middleware<T>): this {
    this.middlewares.push(middleware)
    return this
  }

  // 执行中间件链
  async execute(context: T): Promise<void> {
    const dispatch = (i: number): Promise<void> => {
      if (i >= this.middlewares.length) return Promise.resolve()

      const middleware = this.middlewares[i]
      return Promise.resolve(middleware(context, () => dispatch(i + 1)))
    }

    return dispatch(0)
  }
}
使用示例
ts
import { OnionModel } from './base'

// 使用示例
interface Context {
  count: number
}

// 创建洋葱模型实例
const app = new OnionModel<Context>()

// 添加中间件 - 按顺序执行
app.use(async (ctx, next) => {
  ctx.count++
  console.log('Middleware 1 start', ctx)
  await next()
  console.log('Middleware 1 end', ctx)
})

app.use(async (ctx, next) => {
  ctx.count++
  console.log('Middleware 2 start', ctx)
  await next()
  console.log('Middleware 2 end', ctx)
})

app.use(async (ctx, next) => {
  ctx.count++
  console.log('Middleware 3 start', ctx)
  await next()
  console.log('Middleware 3 end', ctx)
})

// 执行并查看结果
async function run() {
  const context: Context = { count: 0 }
  await app.execute(context)
  console.log('Final result:', context)
}

run()

/* 输出
Middleware 1 start { count: 1 }
Middleware 2 start { count: 2 }
Middleware 3 start { count: 3 }
Middleware 3 end { count: 3 }
Middleware 2 end { count: 3 }
Middleware 1 end { count: 3 }
Final result: { count: 3 }
*/