一元-一元 RPC(双方非流式传输)不允许发送非 ok 状态的响应。对于流式 RPC,服务器可能会在发送错误代码之前发送响应,但不建议这样做。将正常响应与错误状态混合可能会导致未来的可维护性问题,例如,如果相同的错误适用于多个 RPC,是否所有响应 ProtoBuf 消息都应包含这些字段?
回到您的问题,“验证码”应被视为错误状态的一部分,因此可以将其添加为尾随元数据之一。-bin
在您的情况下,您可以通过在尾随元数据键中添加后缀来将序列化的原始消息添加为二进制尾随元数据。
此外,还有一个官方支持的软件包grpcio-status
可以为您执行此操作。
服务器端将丰富的错误状态打包到“grpc_status.status_pb2.Status”原型消息中。下面的示例仅使用常见的错误原型,但您可以将“任何”原型打包到details
中,只要您的客户理解它们。
# Server side
from grpc_status import rpc_status
from google.protobuf import any_pb2
def ...Servicer(...):
def AnRPCCall(request, context):
...
detail = any_pb2.Any()
detail.Pack(
rpc_status.error_details_pb2.DebugInfo(
stack_entries=traceback.format_stack(),
detail="Can't recognize this argument",
)
)
rich_status = grpc_status.status_pb2.Status(
code=grpc_status.code_pb2.INVALID_ARGUMENT,
message='Invalid argument',
details=[detail]
)
context.abort_with_status(rpc_status.to_status(rich_status))
# The method handler will abort
客户端解码错误,并对它们做出反应。
# Client side
try:
self._channel.unary_unary(_ERROR_DETAILS).with_call(_REQUEST)
except grpc.RpcError as rpc_error:
status = rpc_status.from_call(rpc_error)
for detail in status.details:
if detail.Is(error_details_pb2.DebugInfo.DESCRIPTOR):
info = error_details_pb2.DebugInfo()
detail.Unpack(info)
# Handle the debug info
elif detail.Is(OtherErrorProto.DESCRIPTOR):
# Handle the other error proto
else:
# Handle unknown error
详细了解富状态:https ://github.com/grpc/proposal/blob/master/L44-python-rich-status.md