本文最后更新于 826 天前,其中的信息可能已经有所发展或是发生改变。
前言
在微服务框架kratos中,通过中间件对请求进行扩展处理。有点像java里的servlet,也是用的责任链实现的,但实现方式很巧妙,这里详细说一下。
具体实现
处理顺序
┌───────────────────┐
│MIDDLEWARE 1 │
│ ┌────────────────┐│
│ │MIDDLEWARE 2 ││
│ │ ┌─────────────┐││
│ │ │MIDDLEWARE 3 │││
│ │ │ ┌─────────┐ │││
REQUEST │ │ │ │ YOUR │ │││ RESPONSE
──────┼─┼─┼─▷ HANDLER ○─┼┼┼───▷
│ │ │ └─────────┘ │││
│ │ └─────────────┘││
│ └────────────────┘│
└───────────────────┘
Handler
type Handler func(ctx context.Context, req interface{}) (interface{}, error)
- 处理请求,包括协议层处理请求的函数(以下简称为Controller,没想到更合适的词了,反正懂我的意思就行),以及对请求进行扩展的中间件。
Middleware
type Middleware func(Handler) Handler
- 中间件
- 要在Controller处理请求前后,执行扩展代码,就需要在函数内部调用handler,也就是需要一个handler的入参。
- 为啥要返回一个handler?这个handler是增强后的handler,可继续作为入参,进行包装、增强,达到将所有中间件,以及controller串起来的目的。
中间件示例
日志中间件
func loggingMiddleware(handler Handler) Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
println("logging middleware in, req:", req.(string))
reply, err := handler(ctx, req)
println("logging middleware out, reply:", reply.(string))
return reply, err
}
}
认证中间件
func authMiddleware(handler Handler) Handler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
println("auth middleware in, req:", req.(string))
reply, err := handler(ctx, req)
println("auth middleware out, reply:", reply.(string))
return reply, err
}
}
组装责任链
func Chain(m ...Middleware) Middleware {
return func(next Handler) Handler {
for i := len(m) - 1; i >= 0; i-- {
next = m[i](next)
}
return next
}
}
- 注意,这里返回的是函数。这种模式需要消化下,有点链式编程的感觉,拆分了下入参,但缺点就是复杂度的提升。
使用
func main() {
controllerHandler := func(ctx context.Context, req interface{}) (interface{}, error) {
println("hand req")
return "hello " + req.(string), nil
}
handlerChain := Chain(loggingMiddleware, authMiddleware)
chainHeader := handlerChain(controllerHandler)
req := "world"
println("send req:", req)
reply, _ := chainHeader(context.Background(), req)
println("received: ", reply.(string))
}
-
输出
send req: world logging middleware in, req: world auth middleware in, req: world hand req auth middleware out, reply: hello world logging middleware out, reply: hello world received: hello world
每个Middleware都是装饰器:GO编程模式:修饰器——陈皓