我正在用python在grpc-gateway后面编写一个grpc服务,如果某个用户的请求太多,我想引发一个429响应,并在响应消息的正文中提供captcha-token。
实际上,我的问题是,当我使用下面的代码块引发状态代码429之后,我无法发送响应消息。
context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED)
context.set_details('Too many requests')
return MyServiceResponse()据我所知,使用only-grpc是不可能的,但我认为使用第三方可能是可能的。
对此有什么解决方案吗?
发布于 2019-03-14 03:15:21
一元-一元RPC不允许发送非ok状态的响应(两端非流媒体)。对于流式RPC,服务器可能会在发送错误代码之前发送响应,但不建议这样做。混合正常响应和错误状态可能会导致未来的可维护性问题,例如,如果相同的错误适用于多个RPC,所有响应ProtoBuf消息是否都应该包括这些字段?
回到你的问题,"captcha-token“应该被认为是错误状态的一部分,因此它可以被添加为尾随元数据之一。在您的示例中,您可以通过在尾部元数据关键字中添加-bin后缀,将序列化的proto消息作为二进制尾部元数据添加。
此外,还有一个官方支持的包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了解有关rich status的更多信息:https://github.com/grpc/proposal/blob/master/L44-python-rich-status.md
https://stackoverflow.com/questions/55077340
复制相似问题