Ответ
Метаданные в gRPC — это набор пар "ключ-значение", которые передаются вместе с RPC-вызовом, но не являются частью бизнес-логики сообщения (Protobuf). Они очень похожи на HTTP-заголовки и служат для передачи служебной информации.
Основные сценарии использования:
- Аутентификация и авторизация: Передача токенов (JWT, API-ключи) для проверки прав доступа.
- Трассировка и мониторинг: Передача ID трассировки (trace ID) и ID запроса (request ID) для сквозного отслеживания вызовов в микросервисной архитектуре.
- Отладка: Передача отладочной информации, например, имени клиента или версии.
- Управление потоком: Передача информации о сжатии или других параметрах вызова.
Как работать с метаданными в Go:
Метаданные передаются через объект context.Context
.
Пример отправки метаданных клиентом:
import "google.golang.org/grpc/metadata"
// 1. Создаем метаданные
md := metadata.Pairs(
"authorization", "Bearer my-secret-token",
"request-id", "some-unique-id",
)
// 2. Прикрепляем их к контексту
ctx := metadata.NewOutgoingContext(context.Background(), md)
// 3. Выполняем RPC-вызов с этим контекстом
response, err := client.SomeRPC(ctx, request)
Пример чтения метаданных на сервере:
import "google.golang.org/grpc/metadata"
func (s *server) SomeRPC(ctx context.Context, req *pb.Request) (*pb.Response, error) {
// 1. Извлекаем метаданные из входящего контекста
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.InvalidArgument, "Missing metadata")
}
// 2. Читаем значения по ключу (ключи автоматически приводятся к нижнему регистру)
tokens := md.Get("authorization")
if len(tokens) > 0 {
fmt.Println("Auth Token:", tokens[0])
}
// ... остальная логика
return &pb.Response{}, nil
}
Ключевые особенности:
- Ключи метаданных нечувствительны к регистру и автоматически приводятся к
lowercase
. - Для передачи бинарных данных ключ должен иметь суффикс
-bin
. - Существуют также трейлеры (trailers) — это метаданные, которые сервер отправляет в самом конце обработки запроса, вместе со статусом. Они полезны для передачи информации, которая стала известна только по завершении вызова (например, итоговое время обработки).