如果值为 false,gRPC 不会返回布尔值

Sev*_*evy 2 go grpc

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_completedtrue结果就是正确的{"todos": [{"id": "1", "title": "aaa", "isCompleted": true}]}

col*_*tor 5

这是设计使然,也是为了提高效率。

a 的“零”值boolfalse- 因此,当使用值初始化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)
  • 或者,如果您自己导出 JSON,则不使用标准库 ( encoding/json),而是使用JSON此包中的封送拆收器"google.golang.org/protobuf/encoding/protojson"
protojson.Marshaler{EmitDefaults: true}.Marshal(w, resp)
Run Code Online (Sandbox Code Playgroud)

正如这个答案中所概述的。