4

在以下gRPC-client 代码中,第二个是否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") 
}

直觉上,应该总是检查 nilgo 以防万一。但是,有一个运行时检查来捕获任何客户端到服务器的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检查的需要?

4

2 回答 2

4

使用人为的服务器示例进一步调查:

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消息被捕获的位置:

服务器.go

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
    }
    // ...
}

rpc_util.go

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 }

因此,如果对我们的 typed-nil 使用反射,reflect.ValueOf(msg).IsNil()将返回true. 以下c.Marshal(msg)错误 - 并且调用无法向客户端发送消息响应。

于 2019-05-14T20:23:28.877 回答
1

是的,这不应该发生。GRPC 对此负责。

于 2019-05-13T22:50:14.010 回答