问题
I have a working application that accepts SOAP requests, processes the requests, forwards the SOAP request to an API, processes the response, and then forwards the response to the client.
I'm trying to change this application so that it will be JSON between my application and the client but still use SOAP between API and my application
Now, it can successfully accept JSON requests from client and send/receive SOAP with API. However, all the responses to client are empty.
The only case that I receive a non-empty response is when there are validation errors with my JSON request.
Here are some code that might be relevant
app = Application([MyServer],
MY_NAMESPACE,
in_protocol=JsonDocument(validator='soft'),
out_protocol=JsonDocument())
application_server = csrf_exempt(MyDjangoApplication(app))
definition of 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
Definition of MyServer
class MyServer(ServiceBase):
@rpc(MyTestMethodRequest, Sign, **method(_returns=MyTestMethodResponse))
@check_method()
def TestMethod(ctx, request, signature):
response = {
'Data': "test"
}
return response
Definitions of MyTestMethodRequest, MyTestMethodResponse:
class MyTestMethodRequest(ComplexModel):
__namespace__ = MY_NAMESPACE
MyString = String(encoding=STR_ENCODING)
class MyTestMethodResponse(ComplexModel):
__namespace__ = MY_NAMESPACE
Data = String(encoding=STR_ENCODING)
Definition of 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
Definition of 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 ''
Note: Most of these definitions have been simplified (I have removed lines which I think are not relevant)
回答1:
Looking at the code you posted, I can't say I understand what good all those additional decorators and modifiers around arguments do.
Removing them should fix all of your problems.
So let:
class MyTestMethodRequest(ComplexModel):
__namespace__ = MY_NAMESPACE
MyString = Unicode
class MyTestMethodResponse(ComplexModel):
__namespace__ = MY_NAMESPACE
Data = Unicode
Assuming you have the following service:
class MyService(ServiceBase):
@rpc(MyTestMethodRequest, Sign, _returns=MyTestMethodResponse)
def TestMethod(ctx, request, signature):
return MyTestMethodResponse(data="test")
You can have:
app_json = Application([MyService],
MY_NAMESPACE,
in_protocol=JsonDocument(validator='soft'),
out_protocol=JsonDocument())
and
app_soap = Application([MyService],
MY_NAMESPACE,
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11())
which in turn you can pass to DjangoApplication
as usual.:
app_json_dja = csrf_exempt(DjangoApplication(app_json))
app_soap_dja = csrf_exempt(DjangoApplication(app_soap))
which in turn you can mount in Django's url router.
I hope this helps!
来源:https://stackoverflow.com/questions/32520430/spyne-why-am-i-getting-empty-responses-for-json-requests