在 gRPC 单向客户端到服务器流中,服务器可以取消流并向客户端返回错误消息吗?
我尝试设置预告片并使用
.SendAndClose()
返回状态消息,但客户端都无法读取。在客户端,.Send
按预期返回EOF
错误,但.CloseAndRecv()
不返回服务器发送的状态消息,并且.Trailer()
返回空地图。
// 协议缓冲区:
service Foo {
rpc Eat (stream Food) returns (Status) {}
}
// 服务器:
var Retval pb.Status
Retval.Status = "something went wrong"
emap := make(map[string]string)
emap["error"] = "something went wrong"
MD := metadata.New(emap)
Stream.SetTrailer(MD)
Stream.SendAndClose(&Retval)
// 客户:
err = Stream.Send(Stuff) // returns EOF
if err != nil {
Status, err := o.Stream.CloseAndRecv() //returns nil, EOF
MD := o.Stream.Trailer() // returns an empty map.
}
有没有一种方法可以在客户端不使用双向流或单独的 RPC 端点向服务器请求状态消息的情况下实现此目的?
首先,您不需要在原型文件中定义 Status 对象。例如,您可以返回一个名为 Empty 的众所周知的类型。
要执行此操作,您可以执行以下操作:
import "google/protobuf/empty.proto"
service Foo {
rpc Eat (stream Food) returns (google.protobuf.Empty);
}
这只是一个建议,因为您不需要提供 Status 对象。 gRPC 已经定义了一个可以在 go 代码中使用的定义。
然后在服务器端,当你想返回错误时,你不需要调用
SendAndClose
,因为你的Eat
函数将具有以下函数声明:
func (*Server) Eat(stream pb.Foo_EatServer) error
您可以使用类似以下代码的内容来发送指定您有错误的状态。
return nil, status.Errorf(
codes.Internal, // check suitable code
"A description for the error",
)
在返回之前,您可以设置一个预告片,该预告片将在客户端触发错误。
在客户端,您需要执行以下操作:
trailer := stream.Trailer()
v, exist := trailer["error"]
if exist { // there is an error
fmt.Println("Error: ", v)
}
如果您需要更多帮助,请告诉我。