概述

gRPC作为通用RPC框架,内置了拦截器功能。包括服务器端的拦截器和客户端拦截器,使用上大同小异。主要作用是在rpc调用的前后进行额外处理。

从客户端角度讲,可以在请求发起前,截取到请求参数并修改;也可以修改服务器的响应参数。

示例

以下写一个简单的示例来描述具体的功能实现。以Go语言为例,其它语言的gRPC库应该也有类似功能,具体请参考文档。

为使示例简单,简化了对错误的处理。并且只展示了部分代码,完整项目请参考GitHub仓库pnnh/suji-go

接口描述文件

syntax = "proto3";package suji;service Suji {rpc Say(SayRequest) returns (SayReply) {}
}message SayRequest {string msg = 1;
}message SayReply {string msg = 1;
}

最初实现

服务器main方法

func main() {lis, err := net.Listen("tcp", "0.0.0.0:1301")if err != nil {log.Fatalln("监听出错", err)return}grpcServer := grpc.NewServer()suji.RegisterSujiServer(grpcServer, &server.SujiServer{})if err = grpcServer.Serve(lis); err != nil {log.Fatalln("服务停止", err)}
}

客户端main方法

func main() {addr := "127.0.0.1:1301"c := client.LinkSujiServer(addr)rep := client.Say(c, msg)log.Println("收到:", rep.Msg)
}

这里通过LinkSujiServer方法来连接至gRPC服务器,调用了Say接口,并打印了服务器返回值。

LinkSujiServer方法如下

func LinkSujiServer(target string) suji.SujiClient {conn, err := grpc.DialContext(context.Background(), target, grpc.WithInsecure())if err != nil {log.Fatalln("链接至服务出错", err, target)}return suji.NewSujiClient(conn)
}

Say接口客户端调用方式如下:


func Say(client suji.SujiClient, msg string) *suji.SayReply {request := &suji.SayRequest{Msg: msg}reply, err := client.Say(context.Background(), request)if err != nil {log.Fatalln("调用出错", err)}return reply
}

Say接口服务端实现如下,将收到的内容原样返回给调用者:

func (s *SujiServer) Say(ctx context.Context, req *suji.SayRequest) (*suji.SayReply, error) {log.Println("收到:", req.Msg)reply := &suji.SayReply{Msg: req.Msg}return reply, nil
}

运行这段代码,将分别打印以下结果

客户端:

2019/08/15 18:19:59 发送: 你好
2019/08/15 18:19:59 收到: 你好

服务器:

2019/08/15 18:19:59 收到: 你好
2019/08/15 18:19:59 回复: 你好

拦截器实现

原本很简单的接口调用,现在我们通过gRPC客户端拦截器给这段对话加点料。

我们将通过拦截器,截取并篡改客户端发送给服务器的内容,然后把服务器返回的内容也篡改掉。这一切是悄悄在拦截器中进行的,调用的发起方和接收方并不知晓。

定义拦截器方法

func callInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn,invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {if reqParam, ok := req.(*suji.SayRequest); ok {newMsg := strings.Replace(reqParam.Msg, "喜欢", "讨厌", 1)req = &suji.SayRequest{Msg: newMsg}}err := invoker(ctx, method, req, reply, cc, opts...)if err != nil {log.Println("接口调用出错", method, err)return err}if replyParam, ok := reply.(*suji.SayReply); ok {newMsg := strings.Replace(replyParam.Msg, "讨厌", "喜欢", 1)replyParam.Msg = newMsg}return nil
}

方法稍后解释,这里先修改连接服务器的方法,加入拦截器选项:


func LinkSujiServer(target string) suji.SujiClient {conn, err := grpc.DialContext(context.Background(), target, grpc.WithInsecure(),grpc.WithUnaryInterceptor(callInterceptor))if err != nil {log.Fatalln("链接至服务出错", err, target)}return suji.NewSujiClient(conn)
}

注意新增的grpc.WithUnaryInterceptor(callInterceptor)这一行。

gRPC运行时将会为我们定义的callInterceptor传入几个有用的参数。其中method是调用接口的路径,req和reply分别为对应接口的请求和输出参数。而invoker参数是一个方法,用于执行原本的RPC请求,如果调用这个方法,则RPC请求就不会发到服务器。

在这里,我们通过判断请求和响应类型,并对参数进行篡改。同时为了使示例更有趣,简单修改了下main函数代码。

客户端main方法

func main() {addr := "127.0.0.1:1301"c := client.LinkSujiServer(addr)msg := "我喜欢你"log.Println("发送:", msg)rep := client.Say(c, msg)log.Println("收到:", rep.Msg)if strings.Contains(rep.Msg, "喜欢") {log.Println("内心:", "好开心啊")}
}

服务器Say方法

func (s *SujiServer) Say(ctx context.Context, req *suji.SayRequest) (*suji.SayReply, error) {log.Println("收到:", req.Msg)reply := &suji.SayReply{}if strings.Contains(req.Msg, "讨厌") {reply.Msg = "我也讨厌你"}log.Println("回复:", reply.Msg)log.Println("内心:", "沙雕")return reply, nil
}

来看下输出感受下双方的内心吧:

客户端输出:

2019/08/15 19:07:14 发送: 我喜欢你
2019/08/15 19:07:14 收到: 我也喜欢你
2019/08/15 19:07:14 内心: 好开心啊

服务器输出:

2019/08/15 19:07:14 收到: 我讨厌你
2019/08/15 19:07:14 回复: 我也讨厌你
2019/08/15 19:07:14 内心: 沙雕

最后

gRPC除了一元拦截器以外也提供了流拦截器设置方法,通过grpc.WithStreamInterceptor方法在建立连接时设置。流拦截器与一元拦截器功能大致相同,具体应用可参考库源码或相关文档。

转载于:https://www.cnblogs.com/coloc/p/11360071.html

gRPC-拦截器简单使用相关推荐

  1. 第十节——gRPC 拦截器

    第十章--使用 gRPC 拦截器通过 JWT 进行授权 实现一个服务器拦截器来授权使用 JSON Web 令牌 (JWT) 访问我们的 gRPC API.使用这个拦截器,我们将确保只有具有某些特定角色 ...

  2. 获取http请求标头_HTTP请求和标头参数的CDI拦截器–简单示例

    获取http请求标头 在使用Java EE开发和发展REST API的过程中,有些情况下您希望以更精细的方式(视情况)对传入的HTTP请求(特别是标头参数)进行"观察" Servl ...

  3. HTTP请求和标头参数的CDI拦截器-简单示例

    在使用Java EE开发和发展REST API的过程中,有些情况下您希望以更细粒度的方式(视情况而定)对传入的HTTP请求(特别是标头参数)进行"观察" Servlet过滤器或更具 ...

  4. springMVC 拦截器简单配置

    在spring 3.0甚础上,起来越多的用到了注解,从前的拦截器在配置文件中需要这样配置 [html] view plaincopy <beans...> ... <bean id= ...

  5. 手机WIFI拦截器简单实现

    最近,经理给了一个需求,让写一个WIFI拦截器,一开始我也是毫无头绪,不过还是几个小时就搞定了,其实也并没有什么,就是一个简单的广播和服务,上代码: 1.先看一下目录结构: 2.首先你要把你的APP得 ...

  6. SpringMVC拦截器简单使用

    一.拦截器的配置 1.传统的配置 Xml代码   <bean class="org.springframework.web.servlet.mvc.annotation.Default ...

  7. Struts2拦截器简单示例

    拦截器(Interceptor)是Struts 2的核心组成部分.很多功能(Feature)都是构建在拦截器基础之上的,例如文件的上传和下载.国际化.转换器和数据校验等,Struts 2利用内建的拦截 ...

  8. dio拦截器 flutter_详解flutter之网络请求dio,请求,拦截器简单示例

    flutter一直很火的网络请求插件dio 直接上代码,写成一个类,可以直接使用 包含请求的封装,拦截器的封装 import 'package:dio/dio.dart'; import 'dart: ...

  9. MyBatis框架 拦截器简单使用

    Interceptor 是MyBatis提供的一个插件(plugin扩展).代表拦截器,可以拦截代码中的数据库访问操作,即Statement操作 拦截后,可以去修改正在执行的SQL语句,可以额外访问数 ...

  10. 过滤器、拦截器简单流程及使用

    前言 今天咱们来复习一下过滤器与拦截器吧,这是每一个Java程序员都要求掌握的技术,不许说不会哦,不会就赶紧学习,嘿嘿,咱们抓紧时间,现在就开始吧 1. 过滤器与拦截器的差异 过滤器和拦截器在功能上接 ...

最新文章

  1. laravel mysql save 后 查看 受影响行数_swoft2教程系列-mysql模型
  2. 【转】DNS查询过程
  3. Hadoop YARN安装部署初探
  4. 【C语言】通过原子操作实现加减乘除操作Ⅱ
  5. centos rpm
  6. 黑马程序员——java基础---IO(input output)流字符流
  7. 【IDEA】解决: alt+/快捷键 冲突的问题
  8. 计算机网络校园网建设设计摘要,计算机网络专业毕业论文校园网建设设计.doc...
  9. 音量控制 单片机c 语言,(封贴)请大神代写音响音量控制程序(有偿代写)单片机加TDA7313控制...
  10. 斗地主发牌游戏编程java,自己做的斗地主游戏发牌C#程序
  11. 唱歌腹式呼吸法的运用技巧
  12. 下手重了,我把同事小刘的腿打断了...
  13. android 广告平台—杀毒软件是如何知道是否有广告的
  14. 30 年的 Hello world
  15. 安装Linux时grub2安装失败,尝试安装Ubuntu作为计算机唯一的操作系统时,我收到错误'grub-install/dev/sda failed'。 - Ubuntu问答...
  16. 论如何在网页中插入一张图片
  17. mac安全性与隐私 不允许_隐私不仅仅是安全
  18. 10个最佳的大数据处理编程语言
  19. AB测试——流程介绍(设计实验)
  20. 浅析企业即时通讯软件为企业带来的好处有哪些

热门文章

  1. No installations recognized 以及 nvm use切换node版本无效的解决办法
  2. Laravel 中 查询构造器 where 中拼接 wherein 或者orWhere 的写法
  3. android广告页白屏_微信官方朋友圈广告营销技巧
  4. Markdown由浅入深
  5. 直接耦合的互补输出级
  6. video在iPhone浏览器上播放没有声音
  7. aspose html转换pdf,aspose html转pdf java
  8. 红亚2015-3月杯季赛 CTF题部分writeup
  9. 中国数字经济投资态势分析及发展前景深度评估报告2022-2028年版
  10. java中jdbc查询有返回值_使用JdbcTemplate查询方法的返回值 | 学步园