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
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我在数据库中有一条记录 | 编号 | 标题 | 已完成 | |-|-|-| | 1 | 啊啊| 假 |
上面的函数返回{"todos": [{"id": "1", "title": "aaa"}]},但是一旦我将其更改is_completed为true结果就是正确的{"todos": [{"id": "1", "title": "aaa", "isCompleted": true}]}
这是设计使然,也是为了提高效率。
a 的“零”值bool是false- 因此,当使用值初始化protobuf结构时false,在使用标准库的解组器时不需要显式声明该字段encoding/json。在编码端,如果字段的 JSON 标记包含限定符omitempty,标准库的encoding/json封送拆收器将删除任何零值 - 这就是您所看到的。Title如果字符串字段是""(即字符串的零值),您将看到相同的行为。
查看生成的代码 ( *.pb.go),结构体的bool字段定义将如下所示:
type Todo struct {
// ...
IsCompleted bool `protobuf:"varint,5,opt,name=is_complete,proto3" json:"is_complete,omitempty"`
}
Run Code Online (Sandbox Code Playgroud)
因此,json:"...,omitempty"指示encoding/json编组器在使用这些标签进行编组期间省略任何零值。
如果您想覆盖此行为:
omitempty从生成的代码中删除该指令(不推荐 - 因为需要在开发的生命周期中管理编辑)。但如果你必须这样做,请参考这个答案;grpc-gateway,请在运行时覆盖它,例如gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}))
Run Code Online (Sandbox Code Playgroud)
encoding/json),而是使用JSON此包中的封送拆收器"google.golang.org/protobuf/encoding/protojson":protojson.Marshaler{EmitDefaults: true}.Marshal(w, resp)
Run Code Online (Sandbox Code Playgroud)
正如这个答案中所概述的。