Spyne: Почему я получаю пустые ответы на запросы json?

У меня есть работающее приложение, которое принимает запросы SOAP, обрабатывает запросы, перенаправляет запрос SOAP в API, обрабатывает ответ, а затем пересылает ответ клиенту.

Я пытаюсь изменить это приложение так, чтобы оно было в формате JSON между моим приложением и клиентом, но все еще использую SOAP между API и моим приложением

Теперь он может успешно принимать запросы JSON от клиента и отправлять / получать SOAP с API. Тем не менее, все ответы на клиента являются пустыми.

Единственный случай, когда я получаю непустой ответ, - это ошибки валидации с моим 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 ''

Примечание: большинство этих определений были упрощены (я удалил строки, которые, я думаю, не имеют отношения к делу)

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))

который, в свою очередь, можно смонтировать в URL-роутере Django.

Надеюсь, это поможет!

Другие вопросы по тегам