gRPC Header 和 Trailer
gRPC 提供了 Header 和 Trailer 两种元数据机制,用于在客户端和服务端之间传递附加信息。
Header 和 Trailer 的区别
元数据类型 | 发送时机 | 常见用途 |
---|---|---|
Header | RPC 调用开始时,随响应发送 | 包含认证信息、会话数据、请求相关的元信息(如客户端ID)。 |
Trailer | RPC 调用结束时,随结束状态发送 | 传递结束状态、处理统计数据(如耗时)、错误信息等。 |
服务端实现:带认证和性能监控
package mainimport ("context""log""time""google.golang.org/grpc""google.golang.org/grpc/metadata"pb "your_project_path/protos" // 替换为实际的proto包路径
)type MyService struct {pb.UnimplementedYourServiceServer // 嵌套未实现的服务
}func (s *MyService) MyMethod(ctx context.Context, req *pb.MyRequest) (*pb.MyResponse, error) {// 模拟身份验证if err := s.validateAuth(ctx); err != nil {return nil, err}// 设置 Header 元数据header := metadata.Pairs("request-id", req.GetRequestId(),"server-timestamp", time.Now().Format(time.RFC3339),)if err := grpc.SendHeader(ctx, header); err != nil {log.Printf("Failed to send header: %v", err)return nil, err}// 处理业务逻辑start := time.Now()response := &pb.MyResponse{Message: "Hello from the server!",}processTime := time.Since(start)// 设置 Trailer 元数据trailer := metadata.Pairs("status", "success","process-time", processTime.String(),)grpc.SetTrailer(ctx, trailer)return response, nil
}func (s *MyService) validateAuth(ctx context.Context) error {md, ok := metadata.FromIncomingContext(ctx)if !ok {return grpc.Errorf(codes.Unauthenticated, "missing metadata")}authTokens := md["authorization"]if len(authTokens) == 0 || authTokens[0] != "Bearer enterprise-token" {return grpc.Errorf(codes.Unauthenticated, "invalid token")}return nil
}
客户端实现:集成请求追踪和元数据解析
package mainimport ("context""fmt""log""time""google.golang.org/grpc""google.golang.org/grpc/metadata"pb "your_project_path/protos" // 替换为实际的proto包路径
)func main() {conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())if err != nil {log.Fatalf("Failed to connect: %v", err)}defer conn.Close()client := pb.NewYourServiceClient(conn)// 创建上下文并附加元数据ctx := metadata.AppendToOutgoingContext(context.Background(),"authorization", "Bearer enterprise-token","trace-id", "trace-12345",)// 用于接收服务端返回的 Header 和 Trailervar header, trailer metadata.MD// 发起请求resp, err := client.MyMethod(ctx, &pb.MyRequest{RequestId: "req-12345"}, grpc.Header(&header), grpc.Trailer(&trailer))if err != nil {log.Fatalf("RPC failed: %v", err)}// 打印响应fmt.Printf("Response: %s\n", resp.Message)// 打印 Header 和 Trailerfmt.Println("Header received:")for k, v := range header {fmt.Printf(" %s: %v\n", k, v)}fmt.Println("Trailer received:")for k, v := range trailer {fmt.Printf(" %s: %v\n", k, v)}
}
实用场景与注意事项
-
场景:
- Header:验证身份、传递上下文信息,如
auth-token
和trace-id
。 - Trailer:返回状态或统计信息,如
process-time
和status
。
- Header:验证身份、传递上下文信息,如
-
注意事项:
- Header 在响应开始时发送,Trailer 在响应结束后发送。
- 键值均为字符串,推荐键使用小写,遵循 gRPC metadata 规范。
- 使用
trace-id
或类似机制,在分布式系统中实现请求追踪。
示例元数据结构
Header:
request-id: req-12345
server-timestamp: 2025-01-06T10:15:30Z
Trailer:
status: success
process-time: 45ms