9 - grpc 拦截器 —— 从 0 到 1 实现一个拦截器

## grpc 拦截器 —— 从 0 到 1 实现一个拦截器

#### 1、定义结构

    type interceptor func(ctx context.Context, handler func(ctx context.Context) )

    type interceptor func(ctx context.Context, h handler)

type handler func(ctx context.Context)

#### 2、申明赋值

    var h = func(ctx context.Context) {
fmt.Println("do something ...")
}

var inter1 = func(ctx context.Context, h handler) {
fmt.Println("interceptor1")
h(ctx)
}

#### 3、编写执行函数

    func main() {

var ctx context.Context

var ceps []interceptor

var h = func(ctx context.Context) {
fmt.Println("do something ...")
}

var inter1 = func(ctx context.Context, h handler) {
fmt.Println("interceptor1")
h(ctx)
}

ceps = append(ceps, inter1)

for _ , cep := range ceps {
cep(ctx, h)
}

}

    interceptor1
do something ...

ok，我们已经完成了实现这个方法之前 输出一行内容。

       var inter2 = func(ctx context.Context, h handler) {
fmt.Println("interceptor2")
h(ctx)
}

    func main() {

var ctx context.Context

var ceps []interceptor

var h = func(ctx context.Context) {
fmt.Println("do something ...")
}

var inter1 = func(ctx context.Context, h handler) {
fmt.Println("interceptor1")
h(ctx)
}
var inter2 = func(ctx context.Context, h handler) {
fmt.Println("interceptor2")
h(ctx)
}

ceps = append(ceps, inter1, inter2)

for _ , cep := range ceps {
cep(ctx, h)
}

}

    interceptor1
do something ...
interceptor2
do something ...

#### 4、借鉴 grpc-go

    chainUnaryClientInterceptors(cc)

    // chainUnaryClientInterceptors chains all unary client interceptors into one.
func chainUnaryClientInterceptors(cc *ClientConn) {
interceptors := cc.dopts.chainUnaryInts
// Prepend dopts.unaryInt to the chaining interceptors if it exists, since unaryInt will
// be executed before any other chained interceptors.
if cc.dopts.unaryInt != nil {
interceptors = append([]UnaryClientInterceptor{cc.dopts.unaryInt}, interceptors...)
}
var chainedInt UnaryClientInterceptor
if len(interceptors) == 0 {
chainedInt = nil
} else if len(interceptors) == 1 {
chainedInt = interceptors[0]
} else {
chainedInt = func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error {
return interceptors[0](ctx, method, req, reply, cc, getChainUnaryInvoker(interceptors, 0, invoker), opts...)
}
}
cc.dopts.unaryInt = chainedInt
}

chains all unary client interceptors into one. 这句话告诉我们，这个函数把所有拦截器串成了一个拦截器。这是怎么实现的呢？这不就是我们上面碰到的问题吗！来瞅瞅~~~

    // getChainUnaryInvoker recursively generate the chained unary invoker.
func getChainUnaryInvoker(interceptors []UnaryClientInterceptor, curr int, finalInvoker UnaryInvoker) UnaryInvoker {
if curr == len(interceptors)-1 {
return finalInvoker
}
return func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
return interceptors[curr+1](ctx, method, req, reply, cc, getChainUnaryInvoker(interceptors, curr+1, finalInvoker), opts...)
}
}