Golang 优雅实现责任链

前言

在微服务框架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
作者:Yuyy
博客:https://yuyy.info

评论

  1. Yuyy
    博主
    Linux Chrome
    已编辑
    2月前
    2022-10-09 14:22:50

    每个Middleware都是装饰器:GO编程模式:修饰器——陈皓

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇