在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

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. RocketMQ ACL使用指南

    目录 1.什么是ACL? 2.ACL基本流程图 3.如何配置ACL 3.1 acl配置文件 3.2 RocketMQ ACL权限可选值 3.3.权限验证流程 4.使用示例 4.1 Broker端安装 ...

  2. 易初大数据 2019年11月14日 spss笔记 王庆超

    “均匀分布”的随机数 需要打开本章的数据文件“sim.sav.”. 1.设置随机数种子 1选择[转换]--[随机数字生成器],勾选‘设置起点’,并在‘固定值’ 的下‘值’中输入一个用户给定的数值.该数 ...

  3. go中的数据结构字典-map

    1. map的使用 golang中的map是一种数据类型,将键与值绑定到一起,底层是用哈希表实现的,可以快速的通过键找到对应的值. 类型表示:map[keyType][valueType] key一定 ...

  4. BST的实现(二叉搜索树)

    void Inorder(struct Tree *T); //中序 void Preorder(struct Tree *T); //前序 void Postorder(struct Tree *T ...

  5. C#语音特性 很实用

    1.隐式类型 Var 2.匿名类型 new{} 3.自动属性 [prop TAB]  public string Title { get; set; } 4.初始化器  var myObj1 = ne ...

  6. 列转行pivot函数在SQL Sever里面和Oracle里面的用法区别

    首先pivot是一个列转行的函数,反向用是unpivot(行转列). 在SQL sever中可以这么写 SELECT * FROM [TABLE] /*数据源*/ AS A PIVOT ( MAX/* ...

  7. 在Debian/Ubuntu上面安装升级nginx到最新版

    在Debian下面通过 apt-get 可以自动安装 nginx,不过版本一般比较老,如果想要使用nginx的最新特性就需要升级版本.   一般安装可以通过编绎源文件安装,但可能需要安装很多编绎工具, ...

  8. PHP-会话控制Cookie和Session

    会话控制:就是为了我们在访问页面和页面之间的跳转是,能够识别到你的登录状态,已经你的登录时长等 在php的会话控制当中,涉及到两个概念Cookie和Session Cookie 会话控制 原理:在登录 ...

  9. Oracle数据库 获取CLOB字段存储的xml格式字符串指定节点的值

    参照: Oracle存储过程中使用游标来批量解析CLOB字段里面的xml字符串 背景:在写存储过程时,需要获取表单提交的信息.表单信息是以xml格式的字符串存储在colb类型的字段dataxml中,如 ...

  10. Nginx 本地建立负载均衡(Windows环境)

    需求: 现在有个需求:两台服务器,建立负载均衡. A服务器:IP:localhost:负载均衡主服务器:代理本地文件夹D:\\SampleData B服务器:IP:10.10.10.10:代理本地文件 ...