在 gRPC 调用过程中,我们可以拦截 RPC 的执行,在 RPC 服务执行前或执行后运行一些自定义逻辑,这在某些场景下很有用,例如身份验证、日志等,我们可以在 RPC 服务执行前检查调用方的身份信息,若未通过验证,则拒绝执行,也可以在执行前后记录下详细的请求响应信息到日志。这种拦截机制与 Gin 中的中间件技术类似,在 gRPC 中被称为 拦截器,它是 gRPC 核心扩展机制之一

拦截器不止可以作用在服务端上,客户端同样可以拦截,在请求发出之前和收到响应之后执行一些自定义逻辑,根据拦截的 RPC 类型,可分为 一元拦截器流拦截器

服务端拦截器

在 gRPC 服务端,可以插入一个或多个拦截器,收到的请求按注册顺序通过各个拦截器,返回响应时则倒序通过:

一元拦截器

通过以下步骤实现一元拦截器:

  • 定义一元拦截器方法:
// 函数名无特殊要求,参数需一致
// req包含请求的所有信息,info包含一元RPC服务的所有信息
func orderUnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (interface{}, error) {
// 前置处理逻辑
log.Printf("[unary interceptor request] %s", info.FullMethod)
// 完成RPC服务的正常执行
m, err := handler(ctx, req)
// 后置处理逻辑
log.Printf("[unary interceptor resonse] %s", m)
// 返回响应
return m, err
}
  • 注册定义的一元拦截器
func main() {
...
// 创建gRPC服务器实例的时候注册拦截器
// NewServer 可传入多个拦截器
s := grpc.NewServer(grpc.UnaryInterceptor(orderUnaryServerInterceptor))
...
}

流拦截器

流拦截器包括前置处理阶段和流操作阶段,前置处理阶段可以在流 RPC 进入具体服务实现之前进行拦截,而在流操作阶段,可以对流中的每一条消息进行拦截,通过以下步骤实现流拦截器:

  • 自定义一个嵌入grpc.ServerStream的包装器
type wrappedStream struct {
grpc.ServerStream
}
  • 实现包装器的 RecvMsg 和 SendMsg 方法
// 自定义RecvMsg和SendMsg方法实现对每一个流消息的拦截
func (w *wrappedStream) RecvMsg(m interface{}) error {
log.Printf("[stream interceptor recv] type: %T", m)
return w.ServerStream.RecvMsg(m)
}
func (w *wrappedStream) SendMsg(m interface{}) error {
log.Printf("[stream interceptor send] %s", m)
return w.ServerStream.SendMsg(m)
}
  • 实现流拦截器
func orderServerStreamInterceptor(srv interface{}, ss grpc.ServerStream,
info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
// 前置处理阶段
log.Printf("[stream interceptor request] %s", info.FullMethod)
// 使用自定义包装器处理流
err := handler(srv, &wrappedStream{ss})
if err != nil {
log.Printf("[stream Intercept error] %v", err)
}
return err
}
  • 注册流拦截器
func main() {
...
s := grpc.NewServer(grpc.StreamInterceptor(orderServerStreamInterceptor))
...
}

客户端拦截器

在服务端可以拦截收到的 RPC 调用,客户端同样可以拦截发出去的 RPC 请求以及收到的响应,同样可以实现一元拦截器以及流拦截器:

一元拦截器

和服务端一元拦截器一样的方法,只是方法参数略微有所差别,此外在建立连接的时候注册拦截器,同样可以注册多个拦截器:

// method请求方法字符串,req包含请求的所有信息参数等,reply在实际RPC调用后存储响应信息,通过invoker实际调用
func orderUnaryClientInterceptor(ctx context.Context, method string, req, reply interface{},
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
// 前置处理阶段
log.Println("method: " + method)
// 实际的RPC调用
err := invoker(ctx, method, req, reply, cc, opts...)
// 后置处理
log.Println(reply)
return err
} func main() {
...
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithUnaryInterceptor(orderUnaryClientInterceptor))
...
}

流拦截器

流拦截器也是和服务端一样的步骤:

type wrappedStream struct {
grpc.ClientStream
} func (w *wrappedStream) SendMsg(m interface{}) error {
log.Printf("[stream interceptor send] %s", m)
return w.ClientStream.SendMsg(m)
}
func (w *wrappedStream) RecvMsg(m interface{}) error {
log.Printf("[stream interceptor recv] type: %T", m)
return w.ClientStream.RecvMsg(m)
} func orderClientStreamInterceptor(ctx context.Context, desc *grpc.StreamDesc,
cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
// 前置处理阶段,RPC请求发出之前拦截
log.Printf("[client interceptor send] %s", method)
// 发出RPC请求
s, err := streamer(ctx, desc, cc, method, opts...)
if err != nil {
return nil, err
}
return &wrappedStream{s}, nil
} func main() {
...
conn, err := grpc.Dial(address, grpc.WithInsecure(),
grpc.WithStreamInterceptor(orderClientStreamInterceptor))
...
}

gRPC(3):拦截器的更多相关文章

  1. ASP.NET Core 3.0 gRPC 拦截器

    目录 ASP.NET Core 3.0 使用gRPC ASP.NET Core 3.0 gRPC 双向流 ASP.NET Core 3.0 gRPC 拦截器 一. 前言 前面两篇文章给大家介绍了使用g ...

  2. 跟我一起学 Go 系列:gRPC 拦截器

    Go gRPC 学习系列: 跟我一起学Go系列:gRPC 入门必备 第一篇内容我们已经基本了解到 gRPC 如何使用 .对应的三种流模式.现在已经可以让服务端和客户端互相发送消息.本篇仍然讲解功能性的 ...

  3. 源码解析Grpc拦截器(C#版本)

    前言 其实Grpc拦截器是我以前研究过,但是我看网上相关C#版本的源码解析相对少一点,所以笔者借这篇文章给大家分享下Grpc拦截器的实现,废话不多说,直接开讲(Grpc的源码看着很方便,包自动都能还原 ...

  4. gRPC 拦截器能做些什么?

    什么是拦截器? 拦截器是一种横切维度的功能延展. 具象说明一下,高速收费站就是一种拦截器.它可以做什么?收费,查证,交通控制等等,面向所有穿行过往的车辆. gRPC 拦截器主要分为两种:客户端拦截器( ...

  5. grpc中的拦截器

    0.1.索引 https://waterflow.link/articles/1665853719750 当我们编写 HTTP 应用程序时,您可以使用 HTTP 中间件包装特定于路由的应用程序处理程序 ...

  6. Go+gRPC-Gateway(V2) 微服务实战,小程序登录鉴权服务(五):鉴权 gRPC-Interceptor 拦截器实战

    拦截器(gRPC-Interceptor)类似于 Gin 中间件(Middleware),让你在真正调用 RPC 服务前,进行身份认证.参数校验.限流等通用操作. 系列 云原生 API 网关,gRPC ...

  7. 6. ModelDriven拦截器、Preparable 拦截器

    1. 问题 Struts2 的 Action 我们将它定义为一个控制器,但是由于在 Action 中也可以来编写一些业务逻辑,也有人会在 Action 输入业务逻辑层. 但是在企业开发中,我们一般会将 ...

  8. springmvc的拦截器

    什么是拦截器                                                         java里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使 ...

  9. Struts的拦截器

    Struts的拦截器 1.什么是拦截器 Struts的拦截器和Servlet过滤器类似,在执行Action的execute方法之前,Struts会首先执行Struts.xml中引用的拦截器,在执行完所 ...

随机推荐

  1. 创建用户(adduser和useradd)和删除用户(userdel)

    创建用户(adduser和useradd)和删除用户(userdel)及   一  用户创建命令: # adduser  用户名 # useradd  用户名 1) useradd 与 adduser ...

  2. 如何使用ghost备份系统?

    如何使用ghost备份系统? 如何使用ghost工具电脑系统备份?需要具体的详细步骤 关注者 11 被浏览 13,197 关注问题写回答 ​邀请回答 ​添加评论 ​分享 ​     1 个回答 默认排 ...

  3. Jenkins——安装部署

    1.部署Jdk 由于jenkins需要jdk环境,所以先部署jdk,解压并设置环境变量就行: # tar zxf jdk-8u45-linux-x64.tar.gz # mv jdk-8u45-lin ...

  4. FreeRTOS相关转载-(朱工的专栏)

    FreeRTOS系列第1篇---为什么选择FreeRTOS? 1.为什么学习RTOS? 作为基于ARM7.Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS.不仅因为不恰当的使用RTOS ...

  5. android常用的四种对话框java代码

    AlterDialog:确认取消警告提示框 public void showAlertDialog(View view){ AlertDialog.Builder dialog = new Alert ...

  6. mysql数据库-备份与还原-Percona XtraBackup 2.4备份工具使用

    目录 xtrabackup 特点 备份生成的相关文件 xtrabackup 安装 xtrabackup 用法 1 备份 2 预备份 3 还原 4 其他 还原注意事项 xtrabackup实现完全备份及 ...

  7. lighttpd 轻量级WEB服务器

    Lighttpd 是一款开源 Web 服务器软件.Lighttpd 安全快速,符合行业标准,适配性强并且针对高配置环境进行了优化.相对于其它的 Web 服务器而言,Lighttpd 占用内存更少:因其 ...

  8. PHP实现简单的socket与异步应用

    1.socket应用 (1)简单概念 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 建立网络通信连接至少要一对端口号(socket).socket本质是编 ...

  9. Navigation 在fragment之间用bundel传递数据

    使用 Bundle 对象在目的地之间传递参数 如果您不使用 Gradle,仍然可以使用 Bundle 对象在目的地之间传递参数.创建 Bundle 对象并使用 navigate() 将它传递给目的地, ...

  10. openresty 学习笔记三:连接redis和进行相关操作

    openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...