前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang 优雅实现责任链

Golang 优雅实现责任链

作者头像
Yuyy
发布2022-09-13 09:09:35
5000
发布2022-09-13 09:09:35
举报
文章被收录于专栏:yuyy.info技术专栏

前言

在微服务框架kratos中,通过中间件对请求进行扩展处理。有点像java里的servlet,也是用的责任链实现的,但实现方式很巧妙,这里详细说一下。

具体实现

处理顺序

代码语言:javascript
复制
         ┌───────────────────┐
         │MIDDLEWARE 1       │
         │ ┌────────────────┐│
         │ │MIDDLEWARE 2    ││
         │ │ ┌─────────────┐││
         │ │ │MIDDLEWARE 3 │││
         │ │ │ ┌─────────┐ │││
REQUEST  │ │ │ │  YOUR   │ │││  RESPONSE
   ──────┼─┼─┼─▷ HANDLER ○─┼┼┼───▷
         │ │ │ └─────────┘ │││
         │ │ └─────────────┘││
         │ └────────────────┘│
         └───────────────────┘

Handler

代码语言:javascript
复制
type Handler func(ctx context.Context, req interface{}) (interface{}, error)
  • 处理请求,包括协议层处理请求的函数(以下简称为Controller,没想到更合适的词了,反正懂我的意思就行),以及对请求进行扩展的中间件。

Middleware

代码语言:javascript
复制
type Middleware func(Handler) Handler
  • 中间件
  • 要在Controller处理请求前后,执行扩展代码,就需要在函数内部调用handler,也就是需要一个handler的入参。
  • 为啥要返回一个handler?这个handler是增强后的handler,可继续作为入参,进行包装、增强,达到将所有中间件,以及controller串起来的目的。

中间件示例

日志中间件
代码语言:javascript
复制
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
    }
}
认证中间件
代码语言:javascript
复制
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
    }
}

组装责任链

代码语言:javascript
复制
func Chain(m ...Middleware) Middleware {
    return func(next Handler) Handler {
        for i := len(m) - 1; i >= 0; i-- {
            next = m[i](next)
        }
        return next
    }
}
  • 注意,这里返回的是函数。这种模式需要消化下,有点链式编程的感觉,拆分了下入参,但缺点就是复杂度的提升。

使用

代码语言:javascript
复制
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))
}

Post Views: 4

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-9-05 1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 具体实现
    • 处理顺序
      • Handler
        • Middleware
          • 中间件示例
            • 日志中间件
            • 认证中间件
          • 组装责任链
            • 使用
            相关产品与服务
            消息队列 TDMQ
            消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档