iframe的src怎么携带参数_三种传递gRPC动态参数方式的使用体验
gRPC是一個遠程調用框架,使用Protobuf做為信息的載體來完成客戶端和服務端的數據傳輸。關于怎么定義Protobuf消息、搭建gRPC服務在之前的系列文章中都有提及,今天來說一下在使用gRPC和Protobuf的過程中怎么傳遞動態參數。
首先說明一下,這里所說的動態參數指的是在定義Protobuf消息時還不能確定其具體內容的復合類型字段,簡單的說就是消息里的這個字段我們想傳一個類似JSON對象、Map字典、結構體等等這樣的組合值,但是JSON里有哪些字段、每個字段值是什么類型或者Map字典鍵值的類型我們在定義消息時還無法確定(能確定就可以定義子消息嵌套進來了,不在本文的討論范圍內),把這樣的Protobuf消息字段叫做動態參數。
針對通過Protobuf傳遞動態參數的需求,官方文檔里并沒有給出標準的解決方案,目前我所知道的能夠通過bytes、Map以及proto.Struct這三種Protobuf消息字段的類型實現,每種方式也都有自己的優勢和劣處,如果你碰巧知道更好的實現方案,歡迎在評論里留言討論。
下面我們就來看一下使用這三種消息字段的類型如何實現動態參數的傳遞。
使用bytes傳遞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對象對應的結構體類型。
使用Map類型傳遞動態參數
如果你不想通過JSON對象來傳遞參數,另一種經常能想到的方案是把參數的字段類型定義成字典,具體每次調用時可以根據需要設置不同的Key-Value對。Protobuf恰好也有Map類型。
map?map_field?=?N;但是有一點,在定義Map類型時,值的類型必須是固定的,并不支持像map[string]interface{}這樣的值類型。所以這種方式一般是在能確定字典參數的值類型時使用,否則如果定義成了map的話假如要傳遞整型的字段,客戶端還需要先將數據從整型轉換成字符串類型。
使用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?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使用起來感覺也不太方便。這塊如果讀者朋友們相關經驗可以一起來探討一下。
最后做一個投票,針對gRPC動態參數這種需求大家都是怎么解決?
推薦閱讀:gRPC服務注冊發現及負載均衡的實現方案與源碼解析
- END -關注公眾號,每周幫你學會一個進階知識
總結
以上是生活随笔為你收集整理的iframe的src怎么携带参数_三种传递gRPC动态参数方式的使用体验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 量化交易 框架 开源_Hi
- 下一篇: 投资10亿元!比亚迪联合徐工集团共设电池