在这个例子中,我们将在客户端请求和服务器响应中附加头信息。客户端将发送请求头信息,服务器将用头信息进行响应。在这两端,我们将提取头信息。
例子
我不打算显示proto文件,因为它是不相关的。
客户端
package main
import (
"context"
"log"
"strings"
"time"
"pkg/proto/user"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main() {
log.Println("Client running ...")
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
conn, err := grpc.Dial(":50051", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
client := user.NewDeleteServiceClient(conn)
request := &user.DeleteRequest{Uuid: "UUID-123"}
// Anything linked to this variable will transmit request headers.
md := metadata.New(map[string]string{"x-request-id": "req-123"})
ctx = metadata.NewOutgoingContext(ctx, md)
// Anything linked to this variable will fetch response headers.
var header metadata.MD
response, err := client.Delete(ctx, request, grpc.Header(&header))
if err != nil {
log.Fatalln(err)
}
xrid := header["x-response-id"]
if len(xrid) == 0 {
log.Fatalln("missing 'x-response-id' header")
}
if strings.Trim(xrid[0], " ") == "" {
log.Fatalln("empty 'x-response-id' header")
}
log.Println(response.GetCode())
log.Println(xrid[0])
}
服务器
package main
import (
"context"
"log"
"net"
"strings"
"pkg/proto/user"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
type server struct {
user.UnimplementedDeleteServiceServer
}
func main() {
log.Println("Server running ...")
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalln(err)
}
srv := grpc.NewServer()
user.RegisterDeleteServiceServer(srv, &server{})
log.Fatalln(srv.Serve(lis))
}
func (s *server) Delete(ctx context.Context, request *user.DeleteRequest) (*user.DeleteResponse, error) {
// Anything linked to this variable will fetch request headers.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.DataLoss, "failed to get metadata")
}
xrid := md["x-request-id"]
if len(xrid) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "missing 'x-request-id' header")
}
if strings.Trim(xrid[0], " ") == "" {
return nil, status.Errorf(codes.InvalidArgument, "empty 'x-request-id' header")
}
log.Println(request.GetUuid())
log.Println(xrid[0])
// Anything linked to this variable will transmit response headers.
header := metadata.New(map[string]string{"x-response-id": "res-123"})
if err := grpc.SendHeader(ctx, header); err != nil {
return nil, status.Errorf(codes.Internal, "unable to send 'x-response-id' header")
}
return &user.DeleteResponse{Code: 123}, nil
}
测试
$ go run client/main.go
2020/04/08 21:50:17 Client running ...
2020/04/08 21:50:17 123
2020/04/08 21:50:17 res-123 # Test with full header
2020/04/08 21:51:32 missing 'x-response-id' header # Test without header
2020/04/08 21:51:32 empty 'x-response-id' header # Test with empty header
$ go run server/main.go
2020/04/08 21:49:35 Server running ...
2020/04/08 21:49:39 UUID-123
2020/04/08 21:49:39 req-123