golang 中的中间件技术

golang中很多网络相关的库都使用到了一种 middleware 的编程技巧,包括 rpc 和 http。但是这种技巧刚接触很容易搞不清楚概念,在这里记录一下我的理解。

以rpc框架 kite 为例 github地址

kite 作为一个rpc框架,提供了 middleware 的接口,保证多个 rpc 请求可以进行共同的一些配置,包括 超时,LB,日志记录等等。具体代码如下:

// EndPoint represent one method for calling from remote.
type EndPoint func(ctx context.Context, req interface{}) (resp interface{}, err error)

// Middleware deal with input EndPoint and output EndPoint
type Middleware func(EndPoint) EndPoint

// Chain connect middlewares into one middleware.
func Chain(outer Middleware, others ...Middleware) Middleware {
	return func(next EndPoint) EndPoint {
		for i := len(others) - 1; i >= 0; i-- {
			next = others[i](next)
		}
		return outer(next)
	}
}

然后是我自己写的一个例子:


func MW1(next EndPoint) EndPoint {
	return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
		ctx, cancel := context.WithTimeout(ctx, time.Second)
		fmt.Printf("Enter MW1\n")
		defer cancel()
		return next(ctx, req)
	}
}

func MW2(next EndPoint) EndPoint {
	return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
		fmt.Printf("Enter MW2\n")
		return next(ctx, req)
	}
}

func real(ctx context.Context, req interface{}) (resp interface{}, err error) {
	fmt.Printf("Enter real. req: %v\n", req)
	return 1, nil
}

func main() {
	var mw = Chain(MW1, MW2)
	fmt.Printf("finish calling chain\n")
	var resp, err = mw(real)(context.Background(), "hello")
	fmt.Printf("resp: %v error: %v\n", resp, err)
}

最终的打印结果:

finish calling chain
Enter other 0: 0x10a0040
Enter MW1
Enter MW2
Enter real. req: hello
resp: 1 error: <nil>

这里的 EndPoint 和 Middleware 可以这么理解:
EndPoint 是一个处理单元,而 Middleware 可以理解为对一串处理单元的包装,最终适配另一个 EndPoint。如图:

其中 Middleware1 就是蓝色的,它包含了两个 EndPoint,Middleware2 是绿色的,它包含了后面两个 EndPoint,Middleware3 是黄色的,它包含了 Middleware1 和 Middleware2 两个合起来的处理逻辑,也就是说可以通过调用 Chain(Middleware1, Middleware2) 得到 Middleware3。

千万不能将 EndPoint 之间的线认为是 Middleware,因为一个 Middleware 是包含了多个 EndPoint 的。同时,从编码的角度来说,一般中间节点的 EndPoint 逻辑都会写在 Middleware 的匿名函数里面。

最终调用一个中间件时,需要传入一个“叶子”EndPoint,也就是上图中的 EndPoint n,这个EndPoint一般包含了真正的处理逻辑。

posted on 2020-06-29 16:21  daghlny  阅读(1557)  评论(0编辑  收藏  举报

导航