原理:
遍历 ops.interceptors数组,以.interceptors[0]为头,然后传入将数组后面的interceptors依次递归写到下一个handler
实现方式:
- option设置了数组连接器,可以向数组拦截器中添加自己的自定义拦截器!
- 但grpc使用拦截器,最终使用的是将数组拦截器串起来的链式拦截器。
实现方式:
● 判断拦截器数组长度
● 若大于1,将拦截器数组合并成一个链式拦截器
重点:本拦截器处理完,将handler设置成数组的下一个拦截器!
层层套娃的结构
如:
function1(){
function2(){
function3(){
function4(){}
}
}
}
// 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 UnaryClientInterceptorif 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}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...)}}
使用方法:
客户端:
// Set up a connection to the server.
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(creds),
grpc.WithUnaryInterceptor(unaryInterceptor),
grpc.WithStreamInterceptor(streamInterceptor),
grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
服务端
// 服务端使用拦截器
s := grpc.NewServer(
grpc.Creds(creds),
grpc.UnaryInterceptor(unaryInterceptor),
grpc.StreamInterceptor(streamInterceptor))
