代码地址
https://github.com/wanmei002/grpc-learn/tree/master/ch05
介绍
客户端拦截器主要是 内置客户端发送数据前和接收数据后的一些通用逻辑的实现。下图单词拼错了;拦截器:
interceptor
直接上代码吧
一元拦截器
拦截 grpc 的一元模式
需要实现 grpc/interceptor.go/type UnaryClientInterceptor func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
这个类型
func ClientUnaryInterceptor (
ctx context.Context, method string, req, reply interface{},
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opt ...grpc.CallOption,
) error {
log.Printf("method[%v];req[%v];reply[%v];cc[%+v];invoker[%T];\n",
method, req, reply, cc, invoker)
// 上面都是前置逻辑操作
err := invoker(ctx, method, req, reply, cc, opt...)// 向服务端发送请求
// 下面都是后置逻辑操作
if err != nil {
log.Println("invoker err:", err)
}
log.Println("interceptor after")
return err
}
流拦截器的实现
需要实现 grpc/interceptor.go/type StreamClientInterceptor func(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, streamer Streamer, opts ...CallOption) (ClientStream, error)
这个类型
// 实现自定义的接收数据 和 发送数据前的逻辑
type clientStream struct {
grpc.ClientStream
}
// 重写 接收后的逻辑
func (c *clientStream) RecvMsg(m interface{}) error {
log.Printf("recv msg : [%T], val:[%v]\n", m , m)
return c.ClientStream.RecvMsg(m)
}
// 重写 发送前的逻辑
func (c *clientStream) SendMsg(m interface{}) error {
log.Printf("send msg:[%T]; val:[%v]\n", m, m)
return c.ClientStream.SendMsg(m)
}
func NewClientStream(c grpc.ClientStream) grpc.ClientStream {
return &clientStream{c}
}
// 流拦截器的实现
func ClientStreamInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn,
method string, streamer grpc.Streamer, opt ...grpc.CallOption) (grpc.ClientStream, error) {
pc, _, _, _ := runtime.Caller(0)
log.Printf("call method[%v];stream desc[%+v]; method[%v]; streamer[%T];\n",
runtime.FuncForPC(pc).Name(), desc, method, streamer)
// 创建客户端流
s, err := streamer(ctx, desc, cc, method, opt...)
if err != nil {
log.Println("client stream create failed; err:", err)
return nil, err
}
// 流的发送和接收
return NewClientStream(s), nil
}
跑起来
func main(){
// 在这里注册拦截器
d, err := grpc.Dial(":8093", grpc.WithInsecure(),
grpc.WithUnaryInterceptor(interceptor.ClientUnaryInterceptor),// 注册一元拦截器
grpc.WithStreamInterceptor(interceptor.ClientStreamInterceptor))// 注册 流拦截器
if err != nil {
log.Println("grpc dial failed; err:", err)
return
}
defer d.Close()
client := pb.NewProductClient(d)
res, err := client.AddProduct(context.Background(), &pb.Order{
Name: "zzh",
Items: []string{"hello", "zzh"},
Desc: "this is zzh",
})
if err != nil {
log.Println("addProduct ret err; err:", err)
}
log.Printf("addProduct return res:%+v", res)
fmt.Println(res.Code)
stream, err := client.CommentProduct(context.Background(), &pb.ProductId{Id: "1234567"})
if err != nil {
log.Println("client comment product failed; err:", err)
}
log.Println("start recv server stream msg")
if stream != nil {
for {
commentInfo, err := stream.Recv()
if err != nil {
log.Println("client stream recv failed; err:", err)
break
}
log.Printf("recv data :[%+v]\n", commentInfo)
log.Println("once return")
return
}
}
log.Println("client end")
}