如何从grpc-gateway后面的python服务发送非正常状态的响应消息?

时间:2019-03-09 12:26:53

标签: python grpc grpc-python grpc-gateway

我正在python中的grpc-gateway后面编写一个grpc服务,如果某些用户的请求太多,我想提出429个响应,并在响应消息的正文中提供验证码。

实际上,我的问题是,当我使用下面的代码块引发状态代码429之后,我无法发送响应消息。

context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED)
context.set_details('Too many requests')
return MyServiceResponse()

据我了解,only-grpc是不可能的,但是我认为第三方可能会实现。

对此有什么解决办法吗?

1 个答案:

答案 0 :(得分:1)

一元一元RPC不允许发送非正常状态的响应(双方均不流式传输)。对于流式RPC,服务器可以在发送错误代码之前先发送响应,但不建议这样做。将正常响应与错误状态混合在一起可能会导致将来的可维护性问题,例如如果同一错误适用于多个RPC,则所有响应ProtoBuf消息都应包括这些字段吗?

回到您的问题,“验证码令牌”应被视为错误状态的一部分,因此可以将其添加为尾随的元数据之一。对于您自己的情况,可以通过在尾随的元数据密钥中添加一个-bin后缀来将序列化的原始消息作为二进制尾随的元数据添加。

此外,还有一个官方支持的软件包grpcio-status为您完成此任务。

服务器端将丰富的错误状态打包到“ grpc_status.status_pb2.Status”原始消息中。下面的示例仅使用常见的错误原型,但是您可以将“ any”原型打包到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