Go gRPC 学习系列:

  1. 跟我一起学Go系列:gRPC 入门必备

第一篇内容我们已经基本了解到 gRPC 如何使用 、对应的三种流模式。现在已经可以让服务端和客户端互相发送消息。本篇仍然讲解功能性的使用说明:如何使用拦截器。使用过 Java 的同学知道 Spring 或者 Dubbo,这两个框架都提供了拦截器的支持,拦截器的作用无需多言,鉴权,Tracing,数据统计等等。

在 gRPC 中拦截器的实现会稍微有所不同,原因在于 gRPC 多了一种流式数据传输模式。所以这种拦截器的处理也变得相对复杂。

拦截器类型

  1. UnaryServerInterceptor 服务端拦截,在服务端接收请求的时候进行拦截。
  2. UnaryClientInterceptor 这是一个客户端上的拦截器,在客户端真正发起调用之前,进行拦截。
  3. StreamClientInterceptor 在流式客户端调用时,通过拦截 clientstream 的创建,返回一个自定义的 clientstream, 可以做一些额外的操作。
  4. StreamServerInterceptor 在服务端接收到流式请求的时候进行拦截。

拦截器使用

普通拦截器

在 gRPC 中拦截器被定义成一个变量:

type UnaryServerInterceptor func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (resp interface{}, err error)

参数含义如下:

  • ctx context.Context:请求上下文
  • req interface{}:RPC 方法的请求参数
  • info *UnaryServerInfo:RPC 方法的所有信息
  • handler UnaryHandler:RPC 方法真正执行的逻辑

它本质是一个方法,拦截器的应用是在服务端启动的时候要注册上去,从 grpc.NewServer(opts...) 这里开始,这里需要一个 ServerOption 对象:

//注册拦截器 创建gRPC服务器
s := grpc.NewServer(grpc.UnaryInterceptor(LoggingInterceptor))

gRPC 在 v1.28.0 版本增加了多 interceptor 支持,可以在不借助第三方库(go-grpc-middleware)的情况下添加多个 interceptor。看一下 grpc.UnaryInterceptor() 方法的定义:

func UnaryInterceptor(i UnaryServerInterceptor) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
if o.unaryInt != nil {
panic("The unary server interceptor was already set and may not be reset.")
}
o.unaryInt = i
})
}

参数为一个 UnaryServerInterceptor ,即传入 UnaryServerInterceptor 类型的方法即可,所以自定义一个拦截器就变得很简单,只需要定义一个 UnaryServerInterceptor 类型的方法。比如我们实现一个打印日志的拦截器:

//拦截器 - 打印日志
func LoggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (interface{}, error) {
fmt.Printf("gRPC method: %s, %v", info.FullMethod, req)
resp, err := handler(ctx, req)
fmt.Printf("gRPC method: %s, %v", info.FullMethod, resp)
return resp, err
}

可以看到只需要按照 UnaryServerInterceptor 方法的参数去构造即可。然后就是应用,在 server 注册的时候:

grpc.NewServer(grpc.UnaryInterceptor(LoggingInterceptor))  // 创建gRPC服务器
......
......
......

将拦截器注册上就行,是不是很简单。

流拦截器

流拦截器过程和一元拦截器有所不同,同样可以分为3个阶段:

  • 预处理(pre-processing)
  • 调用RPC方法(invoking RPC method)
  • 后处理(post-processing)

预处理阶段的拦截只是在流式请求第一次 发起的时候进行拦截,后面的流式请求不会再进入到处理逻辑。

后面两种情况对应着 Streamer api 提供的两个扩展方法来进行,分别是 SendMsg 和 RecvMsg 方法。

正常情况下实现一个流式拦截器与普通拦截器一样,实现这个已经定义好的拦截器方法即可:

type StreamServerInterceptor func(srv interface{}, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error

如果是想在发消息之前和之进行处理, 则实现 SendMsg 和 RecvMsg:

type wrappedStream struct {
grpc.ServerStream
} func newWrappedStream(s grpc.ServerStream) grpc.ServerStream {
return &wrappedStream{s}
} func (w *wrappedStream) RecvMsg(m interface{}) error {
fmt.Printf("Receive a message (Type: %T) at %s", m, time.Now().Format(time.RFC3339))
return w.ServerStream.RecvMsg(m)
} func (w *wrappedStream) SendMsg(m interface{}) error {
fmt.Printf("Send a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339))
return w.ServerStream.SendMsg(m)
}

首先我们自己包装一个 grpc.ServerStream ,然后去实现它的 SendMsg 和 RecvMsg 方法。然后就是将这个 ServerStream 应用到拦截器中去:

//发消息前后流式调用拦截器
func SendMsgCheckStreamServerInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo,
handler grpc.StreamHandler) error {
fmt.Printf("gRPC method: %s,", info.FullMethod)
err := handler(srv, newWrappedStream(ss))
fmt.Printf("gRPC method: %s", info.FullMethod)
return err
}

这里注意到参数 ss 使用我们自己定义的 ServerStream 包装一下。

相关测试代码都在这里,点击查看

跟我一起学 Go 系列:gRPC 拦截器的更多相关文章

  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. gRPC 拦截器能做些什么?

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

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

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

  4. Android 开发 框架系列 OkHttp拦截器

    前言 此篇博客只讲解okhttp的拦截器功能的详细使用,如果你还不太了解okhttp可以参考我另外一篇博客 Android 开发 框架系列 OkHttp使用详解 添加Interceptor的简单例子 ...

  5. 从 1 开始学 JVM 系列 | JVM 类加载器(一)

    从 1 开始学 JVM 系列 类加载器,对于很多人来说并不陌生.我自己第一次听到这个概念时觉得有点"高大上",觉得只有深入 JDK 源码才会触碰到 ClassLoader,平时都是 ...

  6. 从零开始学 Java - Spring AOP 拦截器的基本实现

    一个程序猿在梦中解决的 Bug 没有人是不做梦的,在所有梦的排行中,白日梦最令人伤感.不知道身为程序猿的大家,有没有睡了一觉,然后在梦中把睡之前代码中怎么也搞不定的 Bug 给解决的经历?反正我是有过 ...

  7. Java内功修炼系列一拦截器

    在动态代理中,我们知道在代理类中,执行真实对象的方法前后可以增加一些其他的逻辑,这些逻辑并不是真实对象能够实现的方法,比如一个租房的用户希望租一套公寓,但是中介所代理的这个房东并没有可以出租的公寓,那 ...

  8. Struts2-学习笔记系列(14)-拦截器

    6.1对action 的拦截 自定义拦截器: public class MyInterceptor extends AbstractInterceptor { private String name; ...

  9. 跟我一起学Go系列:Go gRPC 安全认证机制-SSL/TLS认证

    Go gRPC 系列: 跟我一起学Go系列:gRPC 拦截器使用 跟我一起学Go系列:gRPC 入门必备 第一篇入门说过 gRPC 底层是基于 HTTP/2 协议的,HTTP 本身不带任何加密传输功能 ...

随机推荐

  1. golang:并发编程总结

    并行和并发 并发编程是指在一台处理器上"同时"处理多个任务. 宏观并发:在一段时间内,有多个程序在同时运行. 微观并发:在同一时刻只能有一条指令执行,但多个程序指令被快速的轮换执行 ...

  2. Msf--控制 Android手机

    |>>>中华人民共和国网络安全法<<<|警告:请勿用于非法用途,后果自负! 0.环境 虚拟机 KaliLinux 手机 Redmi 6A 同一局域网下 1.查看控制 ...

  3. Linux 操作系统(一)命令&用户&权限

    以下实例均在Centos7下验证 Centos7 查看命令帮助 man xxx 常用命令 ls / cd - #切到上次目录 cd #回家 cat cat f1 f2 cat f1 f2>f3 ...

  4. 自动做bond的脚本

    #!/bin/bash # 先备份原来的网卡配置文件 find /etc/sysconfig/network-scripts/ -type f -name "ifcfg*"|xar ...

  5. 064.Python开发虚拟环境

    在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题:亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难.此时,我们需要对于不同的工程使用不同 ...

  6. linux(centos 7)下安装JDK,Tomcat,mysql 运行Maven 项目

    一.在Linux中安装JDK 1. 将JDK上传到root下(任何位置均可以). 如图: 2. 用解压命令解压JDK tar -xvf (此处为jdk文件名) 如果是rpm包,执行rpm -i jdk ...

  7. 从Lombok到JSR-269

    前言 Lombok的出现帮助开发人员在开发工程中消除了大部分冗余代码:繁琐的get.set方法甚至建造者模式. Lombok的实现方式是什么呢? 新建一个测试类使用Lombok的Getter和Sett ...

  8. 重新整理 .net core 实践篇—————配置系统之强类型配置[十]

    前言 前文中我们去获取value值的时候,都是通过configurationRoot 来获取的,如configurationRoot["key"],这种形式. 这种形式有一个不好的 ...

  9. [leetcode] 46. 全排列(Java)

    46. 全排列 这题我们可以借用31. 下一个排列写的nextPermutation函数来做,稍微改造一下即可 注意要先给nums排个序 class Solution { // 当没有下一个排列时re ...

  10. 分布式Jmeter压测机的部署

    部署 1.分布式配置 Master机Jmeter安装目录下/bin/jmeter.properties remote_hosts修改为slave压力机的IP 如 remote_hosts=10.0.4 ...