gRPC实践--拦截器

前提阅读:

本文的代码,可能在以上代码的基础上进行了更改。


前言

什么是拦截器?

拦截器(Interceptor),主要完成请求参数的解析、将页面表单参数赋给值栈中相应属性、执行功能检验、程序异常调试等工作。

说人话,就是,我需要在调用 gRPC 方法之前(或之后),对某些参数(如,日志、异常,甚至是token)做一些处理。

实现这类功能的活,就叫“拦截器”。

gRPC中的拦截器

gRPC中,分别对普通方法和流方法提供了截取器的支持,也就是:

  • 一元拦截器:grpc.UnaryInterceptor
  • 流拦截器:grpc.StreamInterceptor

注意:但是,gRPC框架中只能为每个服务设置一个截取器,因此所有的截取工作只能在一个函数中完成。要想为每个服务设置多个不同的拦截器也可以,需要拉取一个开源的依赖包:go-grpc-middleware。在开源的grpc-ecosystem项目中的go-grpc-middleware包已经基于gRPC对截取器实现了链式截取器的支持。

解析

本文重点来看一元拦截器,其实流拦截器也是类似的。grpc.UnaryInterceptor中的结构如下所示

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

其中,UnaryServerInterceptor的接口类似如下所示:

在这里插入图片描述

要实现普通方法的截取器(一元拦截器),就需要为 grpc.UnaryInterceptor 的参数,即UnaryServerInterceptor 实现一个函数。

例子:

func myLogFilter(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	log.Printf("gRPC method: %s, %v", info.FullMethod, req)
	resp, err = handler(ctx, req)
	log.Println("resp is ", resp)
	return resp, err
}

以上,简单实现了一个拦截器。

解释:

  • ctx context.Context:请求上下文
  • req interface{}:RPC 方法的请求参数
  • info *UnaryServerInfo:RPC 方法的所有信息,表示当前是对应的那个gRPC方法
  • handler UnaryHandler:RPC 方法本身,表示对应当前的gRPC方法函数

-----------参考:带入gRPC:Unary and Stream interceptor

使用:

要使用filter截取器函数,只需要在启动gRPC服务时作为参数输入即可:

server := grpc.NewServer(grpc.UnaryInterceptor(myLogFilter))

实现

代码修改

为了代码不用太多的改动,本文在server.go端进行了一定代码修改:

package main

......

// 日志和异常拦截
func myLogFilter(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	// 输出日志
	log.Printf("gRPC method: %s, %v", info.FullMethod, req)
	resp, err = handler(ctx, req)
	// 拦截异常
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("panic: %v", r)
		}
	}()
	log.Println("resp is ", resp)
	return resp, err
}

func main() {
	// 引入证书
	certificate, err := tls.LoadX509KeyPair("server.pem", "server.key")
	......
	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{certificate},
		ClientAuth:   tls.RequireAndVerifyClientCert, // NOTE: this is optional!
		ClientCAs:    certPool,
	})
	// 初始化一个gRPC的结构体对象
    // 开启证书,并传入拦截器
	s := grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(myLogFilter))
	// 注册服务
	pb.RegisterGreeterServer(s, &server{})
	......
}

实验

服务端启动:

go run server.go

客户端启动:

go run client.go

结果:

在这里插入图片描述

多拦截器

注意:但是,gRPC框架中只能为每个服务设置一个截取器,因此所有的截取工作只能在一个函数中完成。要想为每个服务设置多个不同的拦截器也可以,需要拉取一个开源的依赖包:go-grpc-middleware。在开源的grpc-ecosystem项目中的go-grpc-middleware包已经基于gRPC对截取器实现了链式截取器的支持。

以下是go-grpc-middleware包中链式截取器的简单用法

import "github.com/grpc-ecosystem/go-grpc-middleware"

myServer := grpc.NewServer(
    grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
        filter1, filter2, ...
    )),
    grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
        filter1, filter2, ...
    )),
)

----------参考:Go语言高级编程 · 4.5 gRPC进阶

总结

本文主要介绍了gRPC中的拦截器的概念、作用和简单的用法。

具体的深入实践还需要再实际生产过程中进行摸索。

grpc-server-spring-boot-starter是一个基于Spring Boot框架的gRPC服务器的启动器。gRPC(Google Remote Procedure Call)是一种高性能的远程过程调用框架,它使用Protocol Buffers作为接口定义语言,并支持多种编程语言。 grpc-server-spring-boot-starter提供了一系列简化配置和集成的功能,使得在Spring Boot应用中启动和配置gRPC服务器变得更加容易。它提供了自动装配的功能,可以根据应用的配置自动创建和启动gRPC服务器。用户只需要在配置文件中设置相应的参数,如服务器的端口号、TLS证书等,即可完成服务器的启动配置。 在使用grpc-server-spring-boot-starter时,用户可以方便地定义服务接口和实现类。通过使用gRPC的接口定义语言(protobuf)定义接口,并生成对应的Java代码。然后,用户只需要在实现类中实现相应的接口方法即可。 在服务器启动后,grpc-server-spring-boot-starter会根据定义的接口和实现类,自动创建相应的gRPC服务,并将其注册到服务器中。当客户端发起远程调用时,服务器会根据接口定义和方法参数,将请求转发给对应的实现类,并返回执行结果给客户端。 grpc-server-spring-boot-starter还支持对gRPC服务器进行拦截器的配置。拦截器可以在请求和响应的过程中拦截和修改消息,用于实现日志记录、鉴权、性能监控等功能。 总之,grpc-server-spring-boot-starter简化了在Spring Boot应用中使用gRPC的配置和集成过程,使得开发者可以更加便捷地构建和部署gRPC服务器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值