快速图解
简化版代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package main
type Handler func()
var handler Handler = func() {
println("ok")
}
type Middleware func(Handler) Handler
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 middleware1(next Handler) Handler {
return func() {
println("middleware1")
defer func() {
println("middleware1f")
}()
next()
}
}
func middleware2(next Handler) Handler {
return func() {
println("middleware2")
defer func() {
println("middleware2f")
}()
next()
}
}
func middleware3(next Handler) Handler {
return func() {
println("middleware3")
defer func() {
println("middleware3f")
}()
next()
}
}
func main() {
ms := []Middleware{middleware1, middleware2, middleware3}
Chain(ms...)(handler)()
}
/*输出
Chain(ms...)(handler)() 其实对应的形式就是 ms[0](ms[1](ms[2](handler)))()
这样是不是更好理解了
middleware1
middleware2
middleware3
ok
middleware3f
middleware2f
middleware1f
*/
代码赏析
Middleware 处理接口定义
看完上面在看kratos中如何设计的 Middleware 使用 type Handler func(ctx context.Context, req interface{}) (interface{}, error)
用于简化复杂签名
Middleware 的定义是 type func(Handler) Handler
为什么传入一个Handler 在将 Handler 返回呢,其实看到真实的 middleware 的实例就会清楚,传入的 Handler 可以说是 后置的Handler,返回的Handler 是包含了 后置 Handler 与当前 Handler 逻辑新的Handler。
Chain 函数主要用于Handler循环迭代调用,返回最终 Middleware,并将最终调用业务逻辑的handler 传入返回的 Middleware
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package middleware
import (
"context"
)
// Handler defines the handler invoked by Middleware.
type Handler func(ctx context.Context, req interface{}) (interface{}, error)
// Middleware is HTTP/gRPC transport middleware.
type Middleware func(Handler) Handler
// Chain returns a Middleware that specifies the chained handler for endpoint.
func Chain(m ...Middleware) Middleware {
return func(next Handler) Handler {
for i := len(m) - 1; i >= 0; i-- {
next = m[i](next)
}
return next
}
Middleware 调用
kratos 中 middleware 的调用在 transport/http/client.go 处
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func (client *Client) invoke(ctx context.Context, req *http.Request, args interface{}, reply interface{}, c callInfo, opts ...CallOption) error {
//kratos 定义好的调用业务逻辑的handler
h := func(ctx context.Context, in interface{}) (interface{}, error) {
res, err := client.do(req.WithContext(ctx))
if res != nil {
cs := csAttempt{res: res}
for _, o := range opts {
o.after(&c, &cs)
}
}
if err != nil {
return nil, err
}
defer res.Body.Close()
if err := client.opts.decoder(ctx, res, reply); err != nil {
return nil, err
}
return reply, nil
}
var p selector.Peer
ctx = selector.NewPeerContext(ctx, &p)
if len(client.opts.middleware) > 0 {
// kratos 定义好的 调用业务逻辑的handler 传入,迭代调用 后的middleware
h = middleware.Chain(client.opts.middleware...)(h)
}
// 真实调用 包含了kratos定义好的调用业务逻辑的handler 迭代封装后的 middleware
_, err := h(ctx, args)
return err
}
Middleware 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import (
"context"
"github.com/go-kratos/kratos/v2/middleware"
"github.com/go-kratos/kratos/v2/transport"
)
func Middleware1() middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
if tr, ok := transport.FromServerContext(ctx); ok {
// Do something on entering
defer func() {
// Do something on exiting
}()
}
// 在最后需要手动调用 传入的 handler 形成链式调用
return handler(ctx, req)
}
}
}
总结
现在在回过来看middreware 的设计,其实是需要构造一个 链式迭代处理的功能函数,同时配合 golang 的 context 将 context 传给 内层调用函数,保证对context 做的修改可以一直迭代持续下去,最终经过层层middleware处理的 context,传给 Request 的 context ,给业务处理逻辑使用。
如果你看不到评论,那么就真的看不到评论w(゜Д゜)w