GRPC的metadata使用

Stella981
• 阅读 999

文章目录

  • 一、简析

  • 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。

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

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

2、发送metadata

md := metadata.Pairs("key", "val")

// 新建一个有 metadata 的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)

// 单向 RPC
response, err := client.SomeRPC(ctx, someRequest)

更多发送方法见项目文档

3、接收metadata

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

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

二、代码举例

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

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

1、proto文件编写

syntax = "proto3";
package protos;

// The greeting service definition.
service Greeter {
    //   Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {
    }
}

// The request message containing the user's name.
message HelloRequest {
    string name = 1;
}

// The response message containing the greetings
message HelloReply {
    string message = 1;
}

2、server端编写

package main

import (
   "flag"
   "fmt"
   "log"
   "net"
   pb "github.com/zhanben/go_server/protos"

   "golang.org/x/net/context"
   "google.golang.org/grpc"
   "google.golang.org/grpc/metadata"
)


var host = "127.0.0.1"

var (
   ServiceName = flag.String("ServiceName", "hello_service", "service name")
   Port        = flag.Int("Port", 50001, "listening port")

)

func main() {
   flag.Parse()

   lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", *Port))
   if err != nil {
      log.Fatalf("failed to listen: %s", err)
   } else {
      fmt.Printf("listen at:%d\n", *Port)
   }
   defer lis.Close()

   s := grpc.NewServer()
   defer s.GracefulStop()

   pb.RegisterGreeterServer(s, &server{})
   addr := fmt.Sprintf("%s:%d", host, *Port)
   fmt.Printf("server addr:%s\n",addr)

   if err := s.Serve(lis); err != nil {
      fmt.Printf("failed to serve: %s", err)
   }
}

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
   md, ok := metadata.FromIncomingContext(ctx)
   if !ok {
      fmt.Printf("get metadata error")
   }
   if t, ok := md["timestamp"]; ok {
      fmt.Printf("timestamp from metadata:\n")
      for i, e := range t {
         fmt.Printf(" %d. %s\n", i, e)
      }
   }
   //fmt.Printf("%v: Receive is %s\n", time.Now(), in.Name)
   return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

3、client端编写

package main

import (
   "fmt"
   "time"

   pb "github.com/zhanben/go_client/protos"
   "golang.org/x/net/context"
   "google.golang.org/grpc"
   "google.golang.org/grpc/metadata"
)



const (
   timestampFormat = time.StampNano // "Jan _2 15:04:05.000"
)
func main() {

   conn, err := grpc.Dial( "127.0.0.1:50001", grpc.WithInsecure())
   if err != nil {
      panic(err)
   }

   client := pb.NewGreeterClient(conn)
   md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
   ctx := metadata.NewOutgoingContext(context.Background(), md)
   resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "hello, world"})
   if err == nil {
      fmt.Printf("Reply is %s\n", resp.Message)
   }else{
      fmt.Printf("call server error:%s\n", err)
   }

}

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中配置了转发规则,来实现流量控制,达到灰度发布的效果。例如下面的配置

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
      creationTimestamp: null
      name: hello
      namespace: test
    esourceVersion: "0x000000000001158F"
spec:
      hosts:
          - rtsub.uxr
      http:
          - match:
                - headers:
                  key_name://matedata中的key值
                         regex: account=5022222222;.* //exact: account=50222222;

四、参考文件

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
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
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这