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

  1. type MD map[string][]string

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

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

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

  1. md := 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

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

更多发送方法见项目文档

3、接收metadata

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

  1. func (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文件编写

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

2、server端编写

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

3、client端编写

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

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

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: VirtualService
  3. metadata:
  4. creationTimestamp: null
  5. name: hello
  6. namespace: test
  7. esourceVersion: "0x000000000001158F"
  8. spec:
  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

GRPC的metadata使用的更多相关文章

  1. grpc 入门(一)--hello world

    一,从rpc接口的定义说起,下面给一个最简单的grpc示例--hello world 在这个rpc横行的世界里,实现一个rpc很重要的一件事就是定义一个好接口,一个好的接口定义会让你省去很多麻烦.熟悉 ...

  2. gRPC学习

    概述 gRPC 一开始由 google 开发,是一款语言中立.平台中立.开源的远程过程调用(RPC)系统. 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法, ...

  3. Golang gRPC 使用

    一.概念 1.gRPC默认使用protocol buffers,这是google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON),可以用proto files创建gRPC服务 ...

  4. gRPC官方文档(安全认证)

    文章来自gRPC 官方文档中文版 认证 gRPC 被设计成可以利用插件的形式支持多种授权机制.本文档对多种支持的授权机制提供了一个概览,并且用例子来论述对应API,最后就其扩展性作了讨论. 马上将会推 ...

  5. GRPC 截止时间与元数据

    截止时间 gRPC 允许客户端在调用一个远程方法前指定一个最后期限值.这个值指定了在客户端可以等待服务端多长时间来应答,超过这个时间值 RPC 将结束并返回DEADLINE_EXCEEDED错误.在服 ...

  6. btcWallet系列之一-grpc模块

    btcwallet对外服务 btcwallet除了像btcd对外提供rpc服务以外,还提供了grpc服务,同时grpc采用的是protobuf来实现. 这方便与不同语言进行交互,降低客户端代码编写量. ...

  7. 从实践到原理,带你参透 gRPC

    gRPC 在 Go 语言中大放异彩,越来越多的小伙伴在使用,最近也在公司安利了一波,希望这一篇文章能带你一览 gRPC 的巧妙之处,本文篇幅比较长,请做好阅读准备.本文目录如下: 简述 gRPC 是一 ...

  8. Go微服务 grpc/protobuf

    了解grpc/protobuf gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers ...

  9. 【Go】Golang实现gRPC的Proxy的原理

    背景 gRPC是Google开始的一个RPC服务框架, 是英文全名为Google Remote Procedure Call的简称. 广泛的应用在有RPC场景的业务系统中,一些架构中将gRPC请求都经 ...

随机推荐

  1. LNMP+Redis架构部署

    工作机制 L(Linux)N(Nginx)M(Mysql)P(PHP)架构想必大家都知道,LNMP架构主要作用是让前端服务与后端存储以及后端的一下服务进行连接起来,来实现php程序的动态请求. 而今天 ...

  2. 【倒腾HTTPS】Nginx for Docker自签名SSL证书

    前言 合格的web程序员, 必须能自由在 IIS. Nginx. Nginx for Docker上配置Https服务, 博客最近将专题记录 Https  &   Hsts 如何申请适用于生产 ...

  3. PHP yaf显示错误提示

    PHP yaf显示错误提示 1就是配置文件的那个错误 <pre>error_reporting(E_ALL);</pre> 2init.php文件的<pre>fun ...

  4. PHP队列的实现详细操作步骤

    队列是一种特殊的线性表,它只允许在表的前端,可以称之为front,进行删除操作:而在表的后端,可以称之为rear进行插入操作.队列和堆栈一样,是一种操作受限制的线性表,和堆栈不同之处在于:队列是遵循“ ...

  5. [复现论文程序图]High Speed Continuous Variable Source-Independent Quantum Random Number Generation

    这次的任务是复现该文章的图2(C),过程如下. ①翻译了整篇文章,断断续续,花了3-4天时间. ②阅读文章,并且记录下每个符号的意义,记在单独的1个word文档里. ③开始编程,用的matlab201 ...

  6. python:timeit模块

    (鱼c)timeit模块详解——准确测量小段代码的执行时间 http://bbs.fishc.com/forum.php?mod=viewthread&tid=55593&extra= ...

  7. iOS UIView x Android View

  8. PowerDesigner从安装到同步数据库

    前言 最近项目在如火如荼的进行着4.0版本的数据库设计工作,我们几个后端小伙伴也马不停蹄的进行着数据库的设计.使用的设计软件是PowerDesigner,这里记录一些常见的问题以备日后查看 安装 链接 ...

  9. 2019-10-23:渗透测试,基础学习,DVWA,Medium和Hight级别sql注入

    VWA的Medium和Hight级别sql注入 一,Medium级 服务端代码 <?php if( isset( $_POST[ 'Submit' ] ) ) {      // Get inp ...

  10. C语言与汇编语言混合编程实验

    混合编程方法: 模块链接法 汇编指令嵌入法 1: 模块链接法则 模块链接法是指分别用汇编语言和C语言实现独立的模块(或子程序),再用链接程序把各模块生成的obj文件连接成一个可执行程序. 1:C语言调 ...