GRPC的metadata使用

文章目录

  • 一、简析

  • 1、创建metadata

  • 2、发送metadata

  • 3、接收metadata

  • 二、代码举例

  • 1、proto文件编写

  • 2、server端编写

  • 3、client端编写

  • 三、实际使用举例

  • 四、参考文件

在http请求当中我们可以设置header用来传递数据,grpc底层采用http2协议也是支持传递数据的,采用的是metadata。 Metadata 对于 gRPC 本身来说透明, 它使得 client 和 server 能为对方提供本次调用的信息。就像一次 http 请求的 RequestHeader 和 ResponseHeader,http header 的生命周期是一次 http 请求, Metadata 的生命周期则是一次 RPC 调用。

一、简析

项目源代码路径:google.golang.org/grpc/metadata

项目文档路径:https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md

以下翻译自官方文档

1、创建metadata

MD 类型实际上是map,key是string,value是string类型的slice。

type MD map[string][]string

创建的时候可以像创建普通的map类型一样使用new关键字进行创建:

md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})

或者使用Pairs创建,相同的key值会被组合成slice。

1md := metadata.Pairs( 2 "key1", "val1", 3 "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"} 4 "key2", "val2", 5)

key不区分大小写,会被统一转成小写。

2、发送metadata

1md := metadata.Pairs("key", "val") 2 3// 新建一个有 metadata 的 context 4ctx := metadata.NewOutgoingContext(context.Background(), md) 5 6// 单向 RPC 7response, err := client.SomeRPC(ctx, someRequest)

更多发送方法见项目文档

3、接收metadata

利用函数 FromIncomingContext从context中获取metadata:

1func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) { 2 md, ok := metadata.FromIncomingContext(ctx) 3 // do something with metadata 4}

二、代码举例

官方测试项目:https://github.com/grpc/grpc-go/tree/master/examples/features/metadata

详细的使用方法可以参考官方文档,下面是我写的一个简单练手的代码:

1、proto文件编写

1syntax = "proto3"; 2package protos; 3 4// The greeting service definition. 5service Greeter { 6 // Sends a greeting 7 rpc SayHello (HelloRequest) returns (HelloReply) { 8 } 9} 10 11// The request message containing the user's name. 12message HelloRequest { 13 string name = 1; 14} 15 16// The response message containing the greetings 17message HelloReply { 18 string message = 1; 19}

2、server端编写

1package main 2 3import ( 4 "flag" 5 "fmt" 6 "log" 7 "net" 8 pb "github.com/zhanben/go_server/protos" 9 10 "golang.org/x/net/context" 11 "google.golang.org/grpc" 12 "google.golang.org/grpc/metadata" 13) 14 15 16var host = "127.0.0.1" 17 18var ( 19 ServiceName = flag.String("ServiceName", "hello_service", "service name") 20 Port = flag.Int("Port", 50001, "listening port") 21 22) 23 24func main() { 25 flag.Parse() 26 27 lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", *Port)) 28 if err != nil { 29 log.Fatalf("failed to listen: %s", err) 30 } else { 31 fmt.Printf("listen at:%d\n", *Port) 32 } 33 defer lis.Close() 34 35 s := grpc.NewServer() 36 defer s.GracefulStop() 37 38 pb.RegisterGreeterServer(s, &server{}) 39 addr := fmt.Sprintf("%s:%d", host, *Port) 40 fmt.Printf("server addr:%s\n",addr) 41 42 if err := s.Serve(lis); err != nil { 43 fmt.Printf("failed to serve: %s", err) 44 } 45} 46 47// server is used to implement helloworld.GreeterServer. 48type server struct{} 49 50// SayHello implements helloworld.GreeterServer 51func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { 52 md, ok := metadata.FromIncomingContext(ctx) 53 if !ok { 54 fmt.Printf("get metadata error") 55 } 56 if t, ok := md["timestamp"]; ok { 57 fmt.Printf("timestamp from metadata:\n") 58 for i, e := range t { 59 fmt.Printf(" %d. %s\n", i, e) 60 } 61 } 62 //fmt.Printf("%v: Receive is %s\n", time.Now(), in.Name) 63 return &pb.HelloReply{Message: "Hello " + in.Name}, nil 64}

3、client端编写

1package main 2 3import ( 4 "fmt" 5 "time" 6 7 pb "github.com/zhanben/go_client/protos" 8 "golang.org/x/net/context" 9 "google.golang.org/grpc" 10 "google.golang.org/grpc/metadata" 11) 12 13 14 15const ( 16 timestampFormat = time.StampNano // "Jan _2 15:04:05.000" 17) 18func main() { 19 20 conn, err := grpc.Dial( "127.0.0.1:50001", grpc.WithInsecure()) 21 if err != nil { 22 panic(err) 23 } 24 25 client := pb.NewGreeterClient(conn) 26 md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat)) 27 ctx := metadata.NewOutgoingContext(context.Background(), md) 28 resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "hello, world"}) 29 if err == nil { 30 fmt.Printf("Reply is %s\n", resp.Message) 31 }else{ 32 fmt.Printf("call server error:%s\n", err) 33 } 34 35}

root@localhost go_client # ./client
Reply is Hello hello, world

root@localhost go_server # ./server
listen at:50001
server addr:127.0.0.1:50001
timestamp from metadata:

  1. Apr 1 20:25:34.227395377

三、实际使用举例

在项目开发中,我们的某个项目就利用这个metadata传入账户号,然后在envoy中配置了转发规则,来实现流量控制,达到灰度发布的效果。例如下面的配置

1apiVersion: networking.istio.io/v1alpha3 2kind: VirtualService 3metadata: 4 creationTimestamp: null 5 name: hello 6 namespace: test 7 esourceVersion: "0x000000000001158F" 8spec: 9 hosts: 10 - rtsub.uxr 11 http: 12 - match: 13 - headers: 14 key_name://matedata中的key值 15 regex: account=5022222222;.* //exact: account=50222222;

四、参考文件

1、 https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

GRPC的metadata使用 - HelloWorld