gRPC-拦截器简单使用
概述
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方法在建立连接时设置。流拦截器与一元拦截器功能大致相同,具体应用可参考库源码或相关文档。
gRPC-拦截器简单使用的更多相关文章
- gRPC 拦截器能做些什么?
什么是拦截器? 拦截器是一种横切维度的功能延展. 具象说明一下,高速收费站就是一种拦截器.它可以做什么?收费,查证,交通控制等等,面向所有穿行过往的车辆. gRPC 拦截器主要分为两种:客户端拦截器( ...
- 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 ...
- 源码解析Grpc拦截器(C#版本)
前言 其实Grpc拦截器是我以前研究过,但是我看网上相关C#版本的源码解析相对少一点,所以笔者借这篇文章给大家分享下Grpc拦截器的实现,废话不多说,直接开讲(Grpc的源码看着很方便,包自动都能还原 ...
- 跟我一起学 Go 系列:gRPC 拦截器
Go gRPC 学习系列: 跟我一起学Go系列:gRPC 入门必备 第一篇内容我们已经基本了解到 gRPC 如何使用 .对应的三种流模式.现在已经可以让服务端和客户端互相发送消息.本篇仍然讲解功能性的 ...
- springMVC 拦截器简单配置
在spring 3.0甚础上,起来越多的用到了注解,从前的拦截器在配置文件中需要这样配置 <beans...> ... <bean id="measurementInter ...
- struts2拦截器の简单实现(日语系统,请忽略乱码,重在实现)
1.创建类实现interceptor接口或者继承abstractinter~~~类 package com.mi.intercepter; import java.util.Date; import ...
- SpringMVC总结四:拦截器简单介绍
首先要说一下HandlerExecutionChain: HandlerExecutionChain是一个执行链,当用户的请求到达DispatcherServlet的时候,DispatcherServ ...
- struts2拦截器-简单实现非法登录验证
概念:什么是拦截器 拦截器实现了面向切面的组件,它会影响多个业务对象的公共行为封装到一个个可重用的模块,减少了系统的重复代码,实现高度内聚,确保业务对象的整洁! 为什么使用拦截器 拦截器消除了动作 ...
- springMVC拦截器简单配置
<!-- 拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截所 ...
- spring boot的拦截器简单使用
1.spring boot拦截器默认有: HandlerInterceptorAdapter AbstractHandlerMapping UserRoleAuthorizationIntercept ...
随机推荐
- 9-网页,网站,微信公众号基础入门(使用PHP实现微信token验证)
https://www.cnblogs.com/yangfengwu/p/11062422.html 这一节看怎么用PHP实现上一节的功能 关掉上一节的 学了这么久,忘了告诉大家怎么关闭程序了.... ...
- mfs分布式文件系统,分布式存储,高可用(pacemaker+corosync+pcs),磁盘共享(iscsi),fence解决脑裂问题
一.MFS概述 MooseFS是一个分布式存储的框架,其具有如下特性:(1)通用文件系统,不需要修改上层应用就可以使用(那些需要专门api的dfs很麻烦!).(2)可以在线扩容,体系架构可伸缩性极强. ...
- Linux下查看文件和文件夹大小 删除日志
场景:在sts中执行自动部署时候maven提示No space left on device错误,后来经检查发现是磁盘空间满了,用下面的方法分析发现tomcat下面的logs目录占用了很大的空间,删除 ...
- TF 保存模型为 .pb格式
将网络模型,图加权值,保存为.pb文件 write.py # -*- coding: utf-8 -*- from __future__ import absolute_import, unicod ...
- mestasploit笔记 :MS17-010
实验环境 操作机 :Kali 2017 操作机IP:172.16.11.2 目标机:Windows 7 目标机IP:172.16.12.2 实验目的 认知Windows远程溢出漏洞的危害 知悉MS17 ...
- 【转】解决chrome浏览器不支持audio和video标签的autoplay自动播放
声音无法自动播放这个在 IOS/Android 上面一直是个惯例,桌面版的 Safari 在 2017 年的 11 版本也宣布禁掉带有声音的多媒体自动播放功能,紧接着在 2018 年 4 月份发布的 ...
- UDP用于保持大量终端的在线与控制,应用与业务则通过TCP去实现。这个和FTP服务控制与数据分离,采取不同的连接,有异曲同工之处 端口映射老化时间
移动端IM/推送系统的协议选型:UDP还是TCP? http://www.52im.net/thread-33-1-1.html
- servlet是什么?servlet到底是啥?
#说实话 这个鬼servlet我听说过它好多年了,但是我真的不知道它到底是干啥用的.内心里总觉得这是个很复杂的,绝对是让人难以理解的东西,我真的感觉自己很抗拒它,不想知道,不想去了解.可是我还是不得不 ...
- python开源项目聚合推荐【1】
******************************************************* 01项目名:unimatrix 功能介绍:Python模拟“黑客帝国”影片中的终端动画脚 ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器web前端:vue组件之间的传值,父组件向子组件传值
前端方面,EasyDSS流媒体服务器与EasyNVR有着根本的不同.EasyNVR使用的是传统的js来进行开发,而EasyDSS使用的是webpack+vue来进行开发的,了解vue+webpack的 ...