gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中key是string
类型,而value是[]string
,即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周周期是一次http请求,那么metadata的生命周期就是一次RPC调用。
1. go中使用metadata
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"})
//第二种方式 key不区分大小写,会被统一转成小写。
md := metadata.Pairs(
"key1", "val1",
"key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
"key2", "val2",
)
2. 发送metadata
md := metadata.Pairs("key", "val")
// 新建一个有 metadata 的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)
// 单向 RPC
response, err := client.SomeRPC(ctx, someRequest)
3. 接收metadata
func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
md, ok := metadata.FromIncomingContext(ctx)
// do something with metadata
}
2. grpc中使用metadata
1. proto
syntax = "proto3";
option go_package=".;proto";
// 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. client
package main
import (
"OldPackageTest/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main(){
//stream
conn, err := grpc.Dial("127.0.0.1:50051", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
//md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
md := metadata.New(map[string]string{
"name":"yeliangchen",
"pasword":"123456",
})
ctx := metadata.NewOutgoingContext(context.Background(), md)
r, err := c.SayHello(ctx, &proto.HelloRequest{Name:"yeliangchen"})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
3. server
package main
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"net"
"google.golang.org/grpc"
"OldPackageTest/grpc_test/proto"
)
type Server struct{}
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,
error) {
md, ok := metadata.FromIncomingContext(ctx)
if ok {
fmt.Println("get metadata error")
}
if nameSlice, ok := md["name"]; ok {
fmt.Println(nameSlice)
for i, e := range nameSlice {
fmt.Println(i, e)
}
}
return &proto.HelloReply{
Message: "hello " + request.Name,
}, nil
}
func main() {
g := grpc.NewServer()
proto.RegisterGreeterServer(g, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:50051")
if err != nil {
panic("failed to listen:" + err.Error())
}
err = g.Serve(lis)
if err != nil {
panic("failed to start grpc:" + err.Error())
}
}