主题色
250
壁纸模式
壁纸设置
特效设置
固定导航栏
字体选择
文章列表布局
1412 字
4 分钟
中间件/管道链(Middleware / Pipeline Chain)
2026-05-28

一、为什么需要中间件/管道链#

你写了一个 HTTP 服务,最初只有业务逻辑。后来要加日志,就在处理函数开头写几行;要加认证,又在开头加一段校验;要加限流,再加一段计数逻辑。三个月后,业务逻辑被埋在几十行横切代码中间,改一个地方要翻半天。

更麻烦的是顺序问题。如果限流在认证之前运行,未认证的请求也会消耗限流配额,攻击者发一堆无效请求就能耗尽合法用户的配额。这种 bug 不是逻辑错误,而是代码组织方式导致的隐含依赖。

中间件/管道链把每个关注点抽成独立的中间件,按顺序串成链条。每个中间件只做一件事,然后调用 next() 把控制权交给下一个。不调用 next() 就短路整条链。请求向内流入,响应向外流出,形成「洋葱模型」。

二、现实类比#

机场安检通道。你的行李先过 X 光机(日志记录),然后过金属探测器(身份认证),再查验证件(参数校验)。每个关卡只做一件事,然后送你到下一个。任何一个关卡都可以拒绝你通过,相当于不调用 next() 短路整条链。

三、核心思想#

每个中间件接收一个上下文和一个 next() 函数。调用 next() 将控制传递给链中下一个中间件;next() 返回后,中间件可以运行后处理逻辑。不调用 next() 则短路整个链。这创建了一个双向管道,请求向内流入,响应向外流出。

flowchart TD A["中间件 A(日志)"] --> B["中间件 B(认证)"] B --> C["中间件 C(处理器)"] C --> B2["B 后处理"] B2 --> A2["A 后处理"]

执行顺序:A.pre → B.pre → C.pre → C.post → B.post → A.post。即使 B 短路(不调用 next()),A 的后处理仍然会执行,这就是为什么日志中间件即使对被拒绝的请求也能正确记录。

属性值
组合每请求执行 O(n) 个中间件
短路任何中间件可通过不调用 next() 跳过后续
上下文共享所有中间件共享同一个可变上下文对象
方向双向,进入时前处理,返回时后处理

四、变体与对比#

模式关系区别
观察者(Observer)中间件可以观察和修改流经管道的请求/响应观察者是一对多广播,中间件是一对一链
迭代器(Iterator)中间件链像迭代器遍历序列迭代器只读遍历,中间件可修改和短路
注册表(Registry)注册表可以存储和管理链中的中间件注册表管发现,中间件管执行流
虚函数表(Vtable)每个中间件是实现通用接口的函数指针Vtable 是类型分发,中间件是顺序组合

五、多语言实现#

package pipeline
// Handler 是管道终端的处理函数
type Handler func(ctx map[string]any)
// Middleware 是中间件函数,接收上下文和下一个处理器
type Middleware func(ctx map[string]any, next Handler)
// Chain 将多个中间件组合为单一处理器
func Chain(middlewares ...Middleware) Handler {
return func(ctx map[string]any) {
var run func(i int)
run = func(i int) {
if i < len(middlewares) {
// 将后续链包装为 next handler
middlewares[i](ctx, func(c map[string]any) {
run(i + 1)
})
}
}
run(0)
}
}

六、生产验证#

  • gRPC-Go — server.go#L1224-L1260 中的 chainUnaryServerInterceptors 将拦截器链接为单一处理器,getChainUnaryHandler 递归构建链,用于生产 gRPC 服务中的认证、日志、追踪和限流。
  • Koa.js — application.js#L152-L204 中 use() 将中间件推入数组,callback() 通过 koa-compose 组合为单一函数。Koa 开创了异步洋葱模型,每个 await next() 创建一个栈帧,使下游中间件可以使用 try/catch/finally。
  • Express.js — app.use() 链接中间件用于 HTTP 请求处理,是 Node.js 生态最广泛使用的中间件实现。

七、小结#

何时使用:

  • HTTP 请求处理,认证、日志、CORS、压缩、限流作为可组合层
  • RPC 拦截器,gRPC 拦截器用于追踪、认证、重试和指标
  • 构建/编译管道,Webpack loader、Babel 转换各自处理后传递给下一个
  • CLI 命令处理,参数解析、验证、帮助生成作为中间件

何时不用:

  • 事件扇出(一对多),需要多个独立处理器响应同一事件时,用观察者模式
  • 无状态转换,每步只是转换数据不需要包裹下一步时,用 array.map().filter().reduce()
  • 性能关键热路径,每个中间件增加一次函数调用和闭包分配,紧密循环中开销不可忽视

八、参考资料#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

赞助
中间件/管道链(Middleware / Pipeline Chain)
https://blog.souloss.cn/posts/programming/system-patterns/system-patterns-middleware-chain/
作者
Tsukimi
发布于
2026-05-28
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时