在下面的gRPC
-客户端代码中,第二个if
是必需的吗?
status, err := cli.GetStatus(ctx, &empty.Empty{})
if err != nil {
return err
}
if status == nil {
// this should NEVER happen - right?
return fmt.Errorf("nil Status result returned")
}
直觉上,应该总是检查go
中是否为零,以防万一。
但是,存在运行时检查以捕获任何客户端到服务器nil
的使用情况,例如
status, err := cli.GetStatus(ctx, nil) // <- runtime error
if err != nil {
// "rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil"
return err
}
那么,是否存在类似的服务器到客户端运行时保证,从而消除了对status == nil
检查的需要?
答案 0 :(得分:1)
是的,这永远都不会发生。 GRPC对此负责。
答案 1 :(得分:1)
进一步研究人为的服务器示例:
func (s *mygRPC) GetStatus(context.Context, *empty.Empty) (*pb.Status, error) {
log.Println("cli: GetStatus()")
//return &pb.Status{}, nil
return nil, nil // <- can server return a nil status message (with nil error)
}
并测试客户端/服务器的反应:
客户:
ERROR: rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil
服务器:
2019/05/14 16:09:50 cli: GetStatus()
ERROR: 2019/05/14 16:09:50 grpc: server failed to encode response: rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil
因此,即使有人想合法地返回nil值,gRPC
传输也不允许它。
注意:服务器端代码仍按预期执行,但就客户端而言,gRPC
调用失败。
结论:有效(err==nil
)服务器响应将始终返回有效(非nil
)消息。
编辑:
检查gRPC
的源将揭示捕获nil
消息的位置:
func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
if err != nil {
grpclog.Errorln("grpc: server failed to encode response: ", err)
return err
}
// ...
}
func encode(c baseCodec, msg interface{}) ([]byte, error) {
if msg == nil { // NOTE: typed nils will not be caught by this check
return nil, nil
}
b, err := c.Marshal(msg)
if err != nil {
return nil, status.Errorf(codes.Internal, "grpc: error while marshaling: %v", err.Error())
}
// ...
}
此行中的注释是关键:
if msg == nil { // NOTE: typed nils will not be caught by this check }
因此,如果要在我们的类型为nil上使用反射,则reflect.ValueOf(msg).IsNil()
将返回true
。以下c.Marshal(msg)
错误-呼叫无法向客户端发送消息响应。