【gRPC】gRPC拦截器使用指南(客户端、服务端拦截器、拦截器链设置顺序)

您所在的位置:网站首页 shiro拦截器顺序 【gRPC】gRPC拦截器使用指南(客户端、服务端拦截器、拦截器链设置顺序)

【gRPC】gRPC拦截器使用指南(客户端、服务端拦截器、拦截器链设置顺序)

2023-05-11 11:10| 来源: 网络整理| 查看: 265

1.拦截器是什么?

gRPC拦截器(interceptor)是一种函数,它可以在gRPC调用之前和之后执行一些逻辑,例如认证、授权、日志记录、监控和统计等。拦截器函数是gRPC中非常重要的概念,它允许我们在服务端和客户端添加自定义逻辑,以满足业务需求和运维需求。

在gRPC中,拦截器函数通常通过实现grpc.UnaryServerInterceptor和grpc.StreamServerInterceptor接口来定义。UnaryServerInterceptor用于拦截一元RPC请求,而StreamServerInterceptor用于拦截流式RPC请求。在客户端中,我们可以使用grpc.UnaryClientInterceptor和grpc.StreamClientInterceptor来拦截gRPC调用。

在gRPC中,拦截器函数可以被链接起来,形成一个拦截器链。在这个拦截器链中,每个拦截器函数都可以处理请求并将其转发给下一个拦截器函数,或者直接返回响应。因此,我们可以在拦截器函数中编写不同的逻辑,例如实现认证、授权、监控和统计等。

以下是一些常见的gRPC拦截器:

认证和授权拦截器:用于对gRPC调用进行身份验证和权限控制,例如检查token、验证用户名和密码、检查访问控制列表等; 日志记录拦截器:用于记录gRPC调用的日志,例如记录请求的方法、参数、响应状态等; 监控和统计拦截器:用于监控gRPC调用的性能和吞吐量,例如记录调用次数、响应时间、错误率等; 缓存拦截器:用于在服务端或客户端缓存一些数据,例如缓存计算结果、缓存数据库查询结果等。

开源的gRPC拦截器库:

go-grpc-middleware

2.客户端拦截器

在gRPC客户端中,可以使用拦截器来记录日志,客户端的拦截器可以在每个gRPC调用前后执行一些逻辑,例如记录请求和响应的信息。

下面是一个示例,说明如何使用拦截器来记录gRPC调用的日志:

注意,这里使用的是grpc.WithUnaryInterceptor(),与服务器的拦截器方法不同。可以使用ctrl 按住方法直接复制要写的 UnaryInterceptor 函数体

import ( "context" "log" "google.golang.org/grpc" ) func UnaryInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { log.Printf("method=%s, request=%+v", method, req) err := invoker(ctx, method, req, reply, cc, opts...) if err != nil { log.Printf("method=%s, error=%v", method, err) } else { log.Printf("method=%s, response=%+v", method, reply) } return err } func main() { // 创建一个grpc连接,拨号时添加注册拦截器 conn, err := grpc.Dial( "localhost:50051", grpc.WithUnaryInterceptor(UnaryInterceptor), ) if err != nil { log.Fatalf("failed to connect: %v", err) } defer conn.Close() // 创建一个客户端 client := pb.NewMyServiceClient(conn) // 发起一个gRPC调用 resp, err := client.MyMethod(context.Background(), &pb.MyRequest{}) if err != nil { log.Fatalf("failed to call MyMethod: %v", err) } log.Printf("response=%+v", resp) } 复制代码

客户端打印结果:

3.服务端拦截器 import ( "context" "log" "google.golang.org/grpc" ) func UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { log.Printf("method=%s, request=%+v", info.FullMethod, req) resp, err := handler(ctx, req) if err != nil { log.Printf("method=%s, error=%v", info.FullMethod, err) } else { log.Printf("method=%s, response=%+v", info.FullMethod, resp) } return resp, err } func main() { // 创建一个grpc服务器 s := grpc.NewServer( grpc.UnaryInterceptor(UnaryInterceptor), ) // 注册服务 pb.RegisterMyServiceServer(s, &server{}) // 启动服务器 s.Serve(listener) } 复制代码

服务端打印结果:

4.拦截器设置顺序

在gRPC中,拦截器的优先级取决于它们被添加到拦截器链中的顺序。在ChainUnaryInterceptor方法中,第一个拦截器函数将是最外层的函数,而最后一个拦截器函数将是最内层的函数。因此,如果我们想要设置拦截器的优先级,可以通过调整它们的添加顺序来实现。

以下是一个示例,说明如何为两个拦截器函数设置优先级:

import ( "context" "log" "google.golang.org/grpc" ) func LoggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { log.Printf("logging interceptor: method=%s, request=%+v", info.FullMethod, req) resp, err := handler(ctx, req) if err != nil { log.Printf("logging interceptor: method=%s, error=%v", info.FullMethod, err) } else { log.Printf("logging interceptor: method=%s, response=%+v", info.FullMethod, resp) } return resp, err } func AuthInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { log.Printf("auth interceptor: method=%s, request=%+v", info.FullMethod, req) resp, err := handler(ctx, req) if err != nil { log.Printf("auth interceptor: method=%s, error=%v", info.FullMethod, err) } else { log.Printf("auth interceptor: method=%s, response=%+v", info.FullMethod, resp) } return resp, err } func main() { // 创建一个grpc服务器 s := grpc.NewServer( grpc.ChainUnaryInterceptor( LoggingInterceptor, AuthInterceptor, ), ) // 注册服务 pb.RegisterMyServiceServer(s, &server{}) // 启动服务器 s.Serve(listener) } 复制代码

在这个例子中,我们为gRPC服务器添加了两个拦截器函数:LoggingInterceptor和AuthInterceptor。在拦截器链中,LoggingInterceptor将会是最外层的函数,而AuthInterceptor将会是最内层的函数。这意味着LoggingInterceptor将首先被调用,然后再调用AuthInterceptor。

如果我们想要改变它们的顺序,例如将AuthInterceptor放在LoggingInterceptor之前,可以通过调整拦截器的添加顺序来实现。例如,将ChainUnaryInterceptor方法中的拦截器函数列表修改为:

grpc.ChainUnaryInterceptor( AuthInterceptor, LoggingInterceptor, ) 复制代码

这样,AuthInterceptor将会是最外层的函数,而LoggingInterceptor将会是最内层的函数,这样我们就为拦截器函数设置了优先级。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3