gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中key是string
类型,而value是[]string
,即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周期是一次http请求,那么metadata的生命周期就是一次RPC调用。
1.go中使用metadata
源码:https://github.com/grpc/grpc-go/tree/master/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"})
//第二种方式 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,){
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.server
package main
import (
"flag"
"fmt"
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"time"
)
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 err2 := s.Serve(lis);err2!=nil{
fmt.Printf("failed to serve: %s",err2)
}
}
//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,) {
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
}
package main
import (
"OldPackageTest/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"net"
)
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)
}
}
//for key, val := range md{
// fmt.Println(key,val)
//}
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:8080")
if err != nil {
panic("failed to listen" + err.Error())
}
err = g.Serve(lis)
if err != nil {
panic("failed to start" + err.Error())
}
}
3.client
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"time"
)
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)
}
}
package main
import (
"OldPackageTest/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:8080", 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":"golang",
"password":"jetbrains",
})
ctx := metadata.NewOutgoingContext(context.Background(), md)
r, err := c.SayHello(ctx, &proto.HelloRequest{Name: "Anwma"})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}