php小編百草在介紹gRPC的使用時(shí)指出,如果在gRPC請(qǐng)求中,指定的值為false,那么gRPC將不會(huì)返回布爾值。這意味著在使用gRPC時(shí),我們需要注意如何處理返回值,以免造成混淆和錯(cuò)誤。了解這個(gè)細(xì)節(jié)將幫助我們更好地理解和應(yīng)用gRPC的功能,提高我們的編程效率和代碼質(zhì)量。讓我們一起深入研究gRPC的更多特性和用法,為我們的項(xiàng)目帶來(lái)更好的性能和擴(kuò)展性。
問(wèn)題內(nèi)容
func (m *todoserver) gettodos(ctx context.context, empty *emptypb.empty) (*desc.gettodosresponse, error) {
todos, err := m.todoservice.gettodos()
if err != nil {
return nil, err
}
todosresp := make([]*desc.gettodosresponse_todo, 0, len(todos))
for _, todo := range todos {
todosresp = append(todosresp, &desc.gettodosresponse_todo{
id: todo.id,
title: todo.title,
iscompleted: todo.iscompleted,
})
}
return &desc.gettodosresponse{todos: todosresp}, nil
}
登錄后復(fù)制
service TodoService {
rpc GetTodos(google.protobuf.Empty) returns (GetTodosResponse) {}
}
message GetTodosResponse {
repeated Todo todos = 1;
message Todo {
int64 id = 1;
string title = 2;
bool is_completed = 3;
}
}
登錄后復(fù)制登錄后復(fù)制
service TodoService {
rpc GetTodos(google.protobuf.Empty) returns (GetTodosResponse) {}
}
message GetTodosResponse {
repeated Todo todos = 1;
message Todo {
int64 id = 1;
string title = 2;
bool is_completed = 3;
}
}
登錄后復(fù)制登錄后復(fù)制
我在數(shù)據(jù)庫(kù)中有一條記錄
|編號(hào) |標(biāo)題 |已完成 |
|-|-|-|
| 1 |啊啊|假|(zhì)
上面的函數(shù)返回 {"todos": [{"id": "1", "title": "aaa"}]} 但一旦我將 is_completed 更改為 true ,結(jié)果是正確的 {"todos ": [{"id": "1", "title": "aaa", "iscompleted": true}]}
解決方法
這是設(shè)計(jì)使然,也是為了提高效率。
bool 的“零”值是 false – 因此,當(dāng)使用 false 值初始化 protobuf 結(jié)構(gòu)時(shí),在使用標(biāo)準(zhǔn)庫(kù)的 encoding/json 解組器時(shí)不需要顯式聲明該字段。在編碼端,如果字段的 json 標(biāo)記包含 omitempty 限定符,則標(biāo)準(zhǔn)庫(kù)的 encoding/json 封送拆收器將刪除任何零值 – 這就是您所看到的。
如果 title 字符串字段是 "" (即字符串的零值),您將看到相同的行為。
查看生成的代碼(*.pb.go),結(jié)構(gòu)體的 bool 字段定義將如下所示:
type todo struct {
// ...
iscompleted bool `protobuf:"varint,5,opt,name=is_complete,proto3" json:"is_complete,omitempty"`
}
登錄后復(fù)制
因此 json:"...,omitempty" 指示 encoding/json 封送拆收器在使用這些標(biāo)簽進(jìn)行封送期間省略任何零值。
如果您想覆蓋此行為:
可以從生成的代碼中刪除 omitempty 指令(不推薦 – 因?yàn)樾枰陂_(kāi)發(fā)的生命周期中管理編輯)。但如果您必須這樣做,請(qǐng)參閱此答案;
如果使用 grpc-gateway,請(qǐng)?jiān)谶\(yùn)行時(shí)覆蓋它,例如
gwmux := runtime.newservemux(runtime.withmarshaleroption(runtime.mimewildcard, &runtime.jsonpb{origname: true, emitdefaults: true}))
登錄后復(fù)制
或者,如果自己導(dǎo)出 json,則不使用標(biāo)準(zhǔn)庫(kù) (encoding/json),而是使用此包中的 json 封送拆收器 "google.golang.org/protobuf/encoding/protojson":
protojson.Marshaler{EmitDefaults: true}.Marshal(w, resp)
登錄后復(fù)制
如此答案中所述。






