如何使用gRPC状态码并根据客户端构建相应的响应?

huangapple go评论69阅读模式
英文:

How to use grpc status code and build response accordingly to the client?

问题

我正在翻译你的内容,请稍等片刻。

我想知道在将 gRPC 状态码和响应返回给用户时,最佳的处理方式是什么?

func (us *customerService) FetchResponse(ctx context.Context, request *custPbV1.CustomerRequest) (*custPbV1.CustomerResponse, error) {
    meta := service.MetadataFromContext(ctx)
    clientId := meta.ClientId
    if clientId <= 0 {
        msg := fmt.Sprintf("无法检索到客户端信息,clientId:%d", clientId)
        // 这样返回是否正确?
        return nil, status.Error(codes.NotFound, msg)
    }

    resources := request.GetResources()
    if len(resources) == 0 {
        // 这样返回是否正确?
        err := status.Error(codes.InvalidArgument, "值不能为空。(参数 'resources')")
        return nil, err
    }

    return us.GenerateCustomerInfo(clientId, resources)
}

我的 proto 文件非常简单 -

service CustomerService {
   rpc FetchResponse(CustomerRequest) returns (CustomerResponse) {};
}

message CustomerRequest {
   string resources = 1;
}

message CustomerResponse {
   string proc = 1;
   string data = 2;
}

GenerateCustomerInfo 方法将同时返回 CustomerResponseerror。但如果出现错误,那么状态码是什么?我正在尝试弄清楚人们在返回 gRPC 状态码和响应给用户时通常遵循的标准。是否必须将状态码返回给客户端?

在响应对象中添加错误属性是否是一个好主意?任何演示如何返回 gRPC 状态码和响应的最佳实践示例对我都很有用。

英文:

I am wondering what is the best way to deal with grpc status code and response when we sent back to the user?

func (us *customerService) FetchResponse(ctx context.Context, request *custPbV1.CustomerRequest) (*custPbV1.CustomerResponse, error) {
    meta := service.MetadataFromContext(ctx)
    clientId := meta.ClientId
    if clientId &lt;= 0 {
    	msg := fmt.Sprintf(&quot;could not retrieve client info for clientId:%d&quot;, clientId)
        // is this right way to return it?
    	return nil, status.Error(codes.NotFound, msg)
    }

    resources := request.GetResources()
    if len(resources) == 0 {
        // is this right way to return it?
    	err := status.Error(codes.InvalidArgument, &quot;value cannot be null. (Parameter &#39;resources&#39;)&quot;)
    	return nil, err
    }

    return us.GenerateCustomerInfo(clientId, resources)
}

My proto is very simple -

service CustomerService {
   rpc FetchResponse(CustomerRequest) returns (CustomerResponse) {};
}

message CustomerRequest {
   string resources = 1;
}

message CustomerResponse {
   string proc = 1;
   string data = 2;
}

GenerateCustomerInfo method will return CustomerResponse and error both. But if there is a error then what status code it will be? I am trying to figure out what is the standard basically people follow while returning grpc status code and response back to user. Is it mandatory to return status code back to client or no?

Is it good idea to have error property in response object as well? Any example that demonstrates best practice on how to return grpc status and response back will be useful for me.

答案1

得分: 3

这样做完全没问题:

err := status.Error(codes.InvalidArgument, "value cannot be null. (Parameter 'resources')")
return nil, err

这将告诉客户端发生了错误,客户端可以通过检查状态码和状态消息来获取错误信息,如下所示:

resp, err = server.FetchResponse(context.Background(), req)
s, ok := status.FromError(err)

if ok { // 发生了错误
   fmt.Printf("Code: %d, Message: %s\n", s.Code(), s.Message())
}

GenerateCustomerInfo 方法将同时返回 CustomerResponseerror。但如果发生错误,应返回什么状态码?

对于 GenerateCustomerInfo,我们没有太多信息来进行复现,但我认为你应该返回类似以下的内容:

return &custPbV1.CustomerResponse{
	Proc: "YOUR_PROC",
	Data: "YOUR_DATA",
}, nil

通过在错误中返回 nil,你将向客户端显示没有错误,并且在之前的代码中,ok 将为 false

在响应对象中添加错误属性是一个好主意吗?

对于这个问题,你确实可以添加一个错误属性,但是否有必要呢?你已经有了状态码和消息,添加错误属性只会不必要地增加有效载荷的大小。

但是如果 GenerateCustomerInfo 返回任何错误,我应该返回什么状态码?我需要自己定义吗?

假设 GenerateCustomerInfo 的一个潜在实现如下:

func GenerateCustomerInfo() (*pb.CustomerResponse, error) {
	// 一些代码
	if err {
		st := status.Error(codes.Internal /*或其他*/, "一条消息")
		return nil, err
	}

	return &pb.CustomerResponse{
		Proc: "",
		Data: "",
	}, nil
}

它将返回一个 CustomerResponsenil,这完全符合父函数的需求。

英文:

This is totally fine to do it like this:

err := status.Error(codes.InvalidArgument, &quot;value cannot be null. (Parameter &#39;resources&#39;)&quot;)
return nil, err

This will tell your client that there is an error and with that knowledge the client can check the status code and the status message as following:

resp, err = server.FetchResponse(context.Background(), req)
s, ok := status.FromError(err)

if ok { // there is an error
   fmt.Printf(&quot;Code: %d, Message: %s\n&quot;, s.Code(), s.Message())
}

> GenerateCustomerInfo method will return CustomerResponse and error both. But if there is a error then what status code it will be?

For the GenerateCustomerInfo we don't have much info to reproduce but in my opinion you should just return something like:

return &amp;custPbV1.CustomerResponse{
	Proc: &quot;YOUR_PROC&quot;,
	Data: &quot;YOUR_DATA&quot;,
}, nil

by returning nil in the error, you will show the client that there is no error and in the previous code give the ok will be false.

> Is it good idea to have error property in response object as well?

for that, you definitely could add an error property, but is there any need for that? you can already have a StatusCode and a Message. It would just increase the size of your payload unnecessarily.

> But if GenerateCustomerInfo return any error then what status code should I return back? Do I need to define that too?

Given an potential implementation of GenerateCustomerInfo like:

func GenerateCustomerInfo() (*pb.CustomerResponse, error) {
	// some code
	if err {
		st := status.Error(codes.Internal /*or other*/, &quot;a message&quot;)
		return nil, err
	}

	return &amp;pb.CustomerResponse{
		Proc: &quot;&quot;,
		Data: &quot;&quot;,
	}, nil
}

it will basically return either a CustomerResponse or nil which is totally what the parent function need.

huangapple
  • 本文由 发表于 2022年3月3日 13:16:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/71332403.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定