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。

  1. type MD map[string][]string

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

  1. //第一种方式
  2. md := metadata.New(map[string]string{"key1":"val1","key2":"val2"})
  3. //第二种方式 key不区分大小写,会被统一转成小写。
  4. md := metadata.Pairs(
  5. "key1", "val1",
  6. "key1", "val1-2", //"key1" will have map value []string{"val1","val1-2"}
  7. "key2", "val2",
  8. )

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

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

2.grpc中使用metadata

1.proto

  1. syntax = "proto3";
  2. option go_package = ".;proto";
  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. "golang.org/x/net/context"
  8. "google.golang.org/grpc"
  9. "google.golang.org/grpc/metadata"
  10. "time"
  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 err2 := s.Serve(lis);err2!=nil{
  32. fmt.Printf("failed to serve: %s",err2)
  33. }
  34. }
  35. //server is used to implement helloworld.GreeterServer.
  36. type server struct {
  37. }
  38. //SayHello implements helloworld.GreeterServer
  39. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest)(*pb.HelloReply,) {
  40. md,ok := metadata.FromIncomingContext(ctx)
  41. if !ok{
  42. fmt.Printf("get metadata error")
  43. }
  44. if t,ok := md["timestamp"];ok{
  45. fmt.Printf("timestamp from metadata:\n")
  46. for i, e := range t {
  47. fmt.Printf(" %d. %s\n",i,e)
  48. }
  49. }
  50. //fmt.Printf("%v: Receive is %s\n",time.Now(),in.Name)
  51. return &pb.HelloReply{Message:"Hello" + in.Name},nil
  52. }
  1. package main
  2. import (
  3. "OldPackageTest/grpc_test/proto"
  4. "context"
  5. "fmt"
  6. "google.golang.org/grpc"
  7. "google.golang.org/grpc/metadata"
  8. "net"
  9. )
  10. type Server struct {
  11. }
  12. func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
  13. md,ok := metadata.FromIncomingContext(ctx)
  14. if ok{
  15. fmt.Println("get metadata error")
  16. }
  17. if nameSlice,ok:=md["name"];ok{
  18. fmt.Println(nameSlice)
  19. for i, e := range nameSlice {
  20. fmt.Println(i,e)
  21. }
  22. }
  23. //for key, val := range md{
  24. // fmt.Println(key,val)
  25. //}
  26. return &proto.HelloReply{
  27. Message: "hello " + request.Name,
  28. }, nil
  29. }
  30. func main() {
  31. g := grpc.NewServer()
  32. proto.RegisterGreeterServer(g,&Server{})
  33. lis,err := net.Listen("tcp","0.0.0.0:8080")
  34. if err != nil {
  35. panic("failed to listen" + err.Error())
  36. }
  37. err = g.Serve(lis)
  38. if err != nil {
  39. panic("failed to start" + err.Error())
  40. }
  41. }

3.client

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "google.golang.org/grpc"
  6. "google.golang.org/grpc/metadata"
  7. "time"
  8. )
  9. const (
  10. timestampFormat = time.StampNano //"Jan_2 15:04:05.000"
  11. )
  12. func main() {
  13. conn, err := grpc.Dial("127.0.0.1:50001", grpc.WithInsecure())
  14. if err != nil {
  15. panic(err)
  16. }
  17. client := pb.NewGreeterClient(conn)
  18. md := metadata.Pairs("timestamp",time.Now().Format(timestampFormat))
  19. ctx := metadata.NewOutgoingContext(context.Background(),md)
  20. resp,err := client.SayHello(ctx,&pb.HelloRequest{Name:"hello,world"})
  21. if err == nil {
  22. fmt.Printf("Reply is %s\n",resp.Message)
  23. }else{
  24. fmt.Printf("call server error:%s\n",err)
  25. }
  26. }
  1. package main
  2. import (
  3. "OldPackageTest/grpc_test/proto"
  4. "context"
  5. "fmt"
  6. "google.golang.org/grpc"
  7. "google.golang.org/grpc/metadata"
  8. )
  9. func main() {
  10. conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
  11. if err != nil {
  12. panic(err)
  13. }
  14. defer conn.Close()
  15. c := proto.NewGreeterClient(conn)
  16. //md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
  17. md :=metadata.New(map[string]string{
  18. "name":"golang",
  19. "password":"jetbrains",
  20. })
  21. ctx := metadata.NewOutgoingContext(context.Background(), md)
  22. r, err := c.SayHello(ctx, &proto.HelloRequest{Name: "Anwma"})
  23. if err != nil {
  24. panic(err)
  25. }
  26. fmt.Println(r.Message)
  27. }