Spyne:为啥我收到 json 请求的空响应?

Posted

技术标签:

【中文标题】Spyne:为啥我收到 json 请求的空响应?【英文标题】:Spyne: Why am I getting empty responses for json requests?Spyne:为什么我收到 json 请求的空响应? 【发布时间】:2015-09-11 09:44:17 【问题描述】:

我有一个工作应用程序,它接受 SOAP 请求、处理请求、将 SOAP 请求转发到 API、处理响应,然后将响应转发给客户端。

我正在尝试更改此应用程序,以便在我的应用程序和客户端之间使用 JSON,但在 API 和我的应用程序之间仍使用 SOAP

现在,它可以成功接受来自客户端的 JSON 请求并使用 API 发送/接收 SOAP。但是,对客户端的所有响应都是空的。

我收到非空响应的唯一情况是我的 JSON 请求存在验证错误。

这里有一些可能相关的代码

app = Application([MyServer],
              MY_NAMESPACE,
              in_protocol=JsonDocument(validator='soft'),
              out_protocol=JsonDocument())

application_server = csrf_exempt(MyDjangoApplication(app))

MyDjangoApplication 的定义

class MyDjangoApplication(DjangoApplication):
def __call__(self, request, *args, **kwargs):
    retval = self.HttpResponseObject()

    def start_response(status, headers):
        # Status is one of spyne.const.http
        status, reason = status.split(' ', 1)

        retval.status_code = int(status)
        for header, value in headers:
            retval[header] = value

    environ = request.META.copy()

    if request.method == 'POST':
        response = self.handle_rpc(environ, start_response)
    else:
        home_path = reverse('proxy:list_method')

        uri = MY_ENDPOINT_URL or request.build_absolute_uri(home_path)

        # to generate wsdl content
        response = self._WsgiApplication__handle_wsdl_request(environ, start_response, uri)

        if request.path == home_path and _is_wsdl_request(environ):
            fn = None
        elif 'method_name' in kwargs:
            fn = view_method
        else:
            fn = list_method

        if fn:
            return fn(request, app=self, *args, **kwargs)

    self.set_response(retval, response)

    return retval

MyServer的定义

class MyServer(ServiceBase):
    @rpc(MyTestMethodRequest, Sign, **method(_returns=MyTestMethodResponse))
    @check_method()
    def TestMethod(ctx, request, signature):
        response = 
            'Data': "test"
        
        return response

MyTestMethodRequest、MyTestMethodResponse 的定义:

class MyTestMethodRequest(ComplexModel):
    __namespace__ = MY_NAMESPACE

    MyString = String(encoding=STR_ENCODING)


class MyTestMethodResponse(ComplexModel):
    __namespace__ = MY_NAMESPACE

    Data = String(encoding=STR_ENCODING)

check_method的定义:

def check_method(error_handler=None):
    def _check_method(func):
        method_name = func.__name__

        def __check_method(ctx, request, signature, *args, **kwargs):
            if hasattr(request, '__dict__'):
                request = request.__dict__

            if hasattr(signature, '__dict__'):
                signature = signature.__dict__

            response = func(ctx, request or , signature or , *args, **kwargs)

            # setting output protocol
            output_message = generate_out_string(ctx, [response])

            return response

        __check_method.__name__ = method_name
        __check_method.__doc__ = func.__doc__

        return __check_method

    return _check_method

generate_out_string的定义:

def generate_out_string(ctx, objects):
    ctx.out_protocol = ctx.in_protocol

    return _generate_out_string(ctx, objects)

def _generate_out_string(ctx, objects):
    protocol = ctx.out_protocol

    ctx.out_object = objects

    protocol.serialize(ctx, protocol.RESPONSE)
    protocol.create_out_string(ctx)

    out_string = list(ctx.out_string)

    return out_string[0] if out_string else ''

注意:这些定义中的大部分已经被简化(我已经删除了我认为不相关的行)

【问题讨论】:

当你使用普通的 DjangoApplication 时它是否工作?到底有什么问题? 感谢您的回复。使用默认的 DjangoApplication 会产生相同的结果。我不知道为什么要使用自定义 DjangoApplication 的全部细节,但我认为它的主要原因是它只会处理“POST”的请求,否则它将显示一个自定义页面。 好的,请发布服务代码,因为您的 DjangoApplication 子类在这里无关紧要,应用程序实例化看起来很好。 如果是错误我会修复它,如果不是我会告诉你如何修复它,但首先我必须重现它。 已更新。不确定这些是否是您需要的代码。 【参考方案1】:

查看您发布的代码,我不能说我理解所有围绕参数的附加装饰器和修饰符有什么好处。

删除它们应该可以解决您的所有问题。

让我们:

class MyTestMethodRequest(ComplexModel):
    __namespace__ = MY_NAMESPACE

    MyString = Unicode


class MyTestMethodResponse(ComplexModel):
    __namespace__ = MY_NAMESPACE

    Data = Unicode

假设您有以下服务:

class MyService(ServiceBase):
    @rpc(MyTestMethodRequest, Sign, _returns=MyTestMethodResponse)
    def TestMethod(ctx, request, signature):
        return MyTestMethodResponse(data="test")

你可以拥有:

app_json = Application([MyService],
              MY_NAMESPACE,
              in_protocol=JsonDocument(validator='soft'),
              out_protocol=JsonDocument())

app_soap = Application([MyService],
              MY_NAMESPACE,
              in_protocol=Soap11(validator='lxml'),
              out_protocol=Soap11())

然后你可以像往常一样传递给DjangoApplication。:

app_json_dja = csrf_exempt(DjangoApplication(app_json))

app_soap_dja = csrf_exempt(DjangoApplication(app_soap))

你可以挂载到 Django 的 url 路由器中。

我希望这会有所帮助!

【讨论】:

以上是关于Spyne:为啥我收到 json 请求的空响应?的主要内容,如果未能解决你的问题,请参考以下文章

快速删除json响应中的空值

为啥我在 JSON 服务器 POST 请求中收到错误 net::ERR_CONNECTION_REFUSED?

JSON数据请求后的空对象

当我使用 HTTP 协议尝试请求时,为啥会收到错误的请求响应?

使用 Latin-1 编码 Spyne SOAP XML 响应

为啥我的 Servlet 不响应 UTF-8 格式的 JSON 请求?