gRPC
это инфраструктура удаленного вызова, которая используетProtobuf
В качестве носителя информации для завершения передачи данных между клиентом и сервером. О том, как определитьProtobuf
новости, сборкаgRPC
служил раньшесерия статейбыли упомянуты вgRPC
иProtobuf
Как передать динамические параметры в процессе.
Прежде всего, позвольте мне объяснить, что упомянутые здесь динамические параметры относятся к определениюProtobuf
Поле составного типа конкретного контента не может быть определено при отправке сообщения.Проще говоря, именно это поле в сообщении.Мы хотим передать аналогичныйJSON
объект,Map
составные значения, такие как словари, структуры и т. д., ноJSON
Какие поля есть, какого типа значение каждого поля илиMap
Тип ключей словаря в нашем пользовательском сообщении Shihai не может быть определен (можно определить, может ли определить вложенное подсообщение, выходящее за рамки этой статьи), что такоеProtobuf
Поля сообщения называются динамическими параметрами.
за прохождениеProtobuf
Стандартного решения требования передачи динамических параметров в официальной документации нет.bytes
,Map<string, string>
а такжеproto.Struct
эти троеProtobuf
Тип реализации поля сообщения, каждый метод также имеет свои преимущества и недостатки, если вы знаете лучший план реализации, оставьте сообщение в комментариях для обсуждения.
Давайте посмотрим, как использовать эти три типа полей сообщений для динамической передачи параметров.
Передайте параметр объекта JSON, используя байты
Protobuf
внутреннийbytes
Поля типа кодируются какGo
Соответствующий код после кодаGo
байтовый срез в[]byte
тип. Таким образом, мы можем определить тип поля динамического параметра какbytes
типа, чтобы клиент поставилJSON
После того, как объект передан на сервер, сервер может напрямуюJSON
Объект выполняет операцию декодирования, устраняя необходимость вstring
прибыть[]byte
преобразование типов.
Например, в следующемProtobuf
в определении сообщенияinfo
Тип поляbytes
rpc UpdateRecord (UpdateRecordRequest) returns (UpdateRecordReply) {
}
message UpdateRecordRequest {
int64 id = 1;
bytes info = 2;
}
Затем при использовании этого метода gRPC, когда клиент использует его, он напрямую ставитinfo
передача данныхjson.Marshal
После кодирования его можно передать на сервер.
info := struct {
name string
age int
} {
name: "James",
age: 20,
}
jsonInfo, _ := json.Marshal(info)
_ := AppService.UpdateRecord(&AppService.UpdateRecordRequest{id: 2, info: jsonInfo})
На стороне сервера можно добавить проверку параметра, чтобы убедиться, что он передан правильно.JSON
объект.
func IsJSON(in []byte) bool {
var js map[string]interface{}
return json.Unmarshal(in, &js) == nil
}
После проверки вы можете декодировать динамические параметры в соответствии с фактическими требованиями использования.JSON
Объект разрешается в определенную структурную переменную.
type Info struct {
name string `json:"name"`
age int `json:"id"`
}
func (s server) UpdateRecord(ctx context.Context, reqeust *AppService.UpdateRecordRequest) (reply *AppService.UpdateRecordReply, err error) {
if !isJson(req.Info) {
// 错误处理
...
}
v := Info{}
json.Unmarshal(req.Info, $v)
}
Я обычно использую этот метод, он кажется более удобным, единственная проблема в том, что каждое место, которое использует динамические параметры, должно определять и анализировать само по себеJSON
Тип структуры, соответствующий объекту.
Передайте динамические параметры, используя тип карты
Если вы не хотите проходитьJSON
объект для передачи параметров, другое решение, о котором часто можно подумать, состоит в том, чтобы определить тип поля параметра как словарь, и каждый вызов может быть установлен в соответствии с различными потребностями.Key-Value
правильно.Protobuf
случилось иметьMap
тип.
map<key_type, value_type> map_field = N;
Но есть одно но, в определенииMap
тип, тип значения должен быть фиксированным и не поддерживает такие вещи, какmap[string]interface{}
такой тип значения.Таким образом, этот метод обычно используется, когда можно определить тип значения параметра словаря., в противном случае, если он определен какmap<string, string>
Если вы хотите передать целочисленное поле, клиенту также необходимо сначала преобразовать данные из целочисленного типа в строковый.
Используйте proto.Struct для передачи динамических параметров структуры
В некоторых источниках упоминается использованиеProtobuf
Он поставляется с составным типомproto.Struct
Передавая параметры динамического типа, преимущество его использования в том, что он выглядит какProtobuf
Встроенная поддержка динамически типизированных данных, которую вы можете использоватьProtobuf
собственный пакетjsonpb
завершить отJSON
прибытьproto.Struct
преобразование между.
использоватьproto.Struct
тип должен быть вproto
Сначала файл вводит определение своего типа, как показано ниже.
syntax = "proto3";
package messages;
import "google/protobuf/struct.proto";
service UserService {
rpc SendJson (SendJsonRequest) returns (SendJsonResponse) {}
}
message SendJsonRequest {
string UserID = 1;
google.protobuf.Struct Details = 2;
}
message SendJsonResponse {
string Response = 1;
}
пройти черезproto.Struct
Базовые определения исходного кода могут видеть, что на самом деле это человек по имениStruct
, который содержит толькоfiledsизMap
поле типа, черезProtobuf
изOneof
особенность указываетMap
Диапазон типов значения аппроксимируется для завершения поддержки динамического типа.
message Struct {
// Unordered map of dynamically typed values.
map<string, Value> fields = 1;
}
message Value {
// The kind of value.
oneof kind {
// Represents a null value.
NullValue null_value = 1;
// Represents a double value.
double number_value = 2;
// Represents a string value.
string string_value = 3;
// Represents a boolean value.
bool bool_value = 4;
// Represents a structured value.
Struct struct_value = 5;
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
Так действуйте при использованииproto.Struct
Что-то вроде манипулирования словарями, вот пример его использования.
func sendJson(userClient pb.UserServiceClient, ctx context.Context) {
var item = &structpb.Struct{
Fields: map[string]*structpb.Value{
"name": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "James",
},
},
"age": &structpb.Value{
Kind: &structpb.Value_NumberValue{
NumberValue: 20,
},
},
},
}
userGetRequest := &pb.SendJsonRequest{
UserID: "A123",
Details: item,
}
res, err := userClient.SendJson(ctx, userGetRequest)
}
Суммировать
Суммируя три метода, я все же считаю, что первый более удобен в использовании, второй может ограничивать тип значения только единицей, в противном случае нужно делать преобразование типов на клиенте и сервере, третий тоже может найти в сети.proto.Struct
Использование меньшего количества информации, более сложное для начала и не такое гибкое, как первое. Кроме тогоProtobuf
есть еще одинAny
Тип, давайте не нужно определить сообщение, когда мы его используем, но нам нужно нести данные о описанииurl
Пользоваться им не удобно. Эту часть можно обсуждать, если можно обсудить связанный с ней опыт читателя.
Смотрите здесь, если вам понравилась моя статья, вы можете поставить мне лайк, я буду делиться своими знаниями и практическим опытом из первых рук в технических статьях каждую неделю, спасибо за вашу поддержку. Поиск в WeChat и подписка на общедоступную учетную запись «Управление сетью Наоби Нао» каждую неделю обучают вас углубленным знаниям, а также есть вводные руководства по Kubernetes, специально написанные для инженеров-разработчиков.