J'implémente un service Web SOAP en utilisant tornado (et le module tiers tornadows). L'une des opérations dans mon service doit appeler un autre, donc j'ai la chaîne:Appels de service Web imbriqués avec tornade (async?)
- demande externe (via l'SoapUI) à l'opération A
- demande interne (via le module de requêtes) pour le fonctionnement B
- réponse interne du fonctionnement B
- de réponse externe de l'opération A
Parce qu'il est en cours d'exécution tout en un seul service, il est bloqué quelque part bien. Je ne suis pas familier avec la fonctionnalité asynchrone de tornado.
Il existe une seule méthode de traitement des requêtes (post) car tout arrive sur l'URL unique, puis l'opération spécifique (méthode de traitement) est appelée en fonction de la valeur de l'en-tête de requête SOAPAction. J'ai décoré ma méthode post avec @ tornado.web.asynchronous et appelé self.finish() à la fin mais pas de dés.
Peut tornado gérer ce scénario et si oui, comment puis-je l'implémenter?
EDIT (code ajouté):
class SoapHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def post(self):
""" Method post() to process of requests and responses SOAP messages """
try:
self._request = self._parseSoap(self.request.body)
soapaction = self.request.headers['SOAPAction'].replace('"','')
self.set_header('Content-Type','text/xml')
for operations in dir(self):
operation = getattr(self,operations)
method = ''
if callable(operation) and hasattr(operation,'_is_operation'):
num_methods = self._countOperations()
if hasattr(operation,'_operation') and soapaction.endswith(getattr(operation,'_operation')) and num_methods > 1:
method = getattr(operation,'_operation')
self._response = self._executeOperation(operation,method=method)
break
elif num_methods == 1:
self._response = self._executeOperation(operation,method='')
break
soapmsg = self._response.getSoap().toprettyxml()
self.write(soapmsg)
self.finish()
except Exception as detail:
#traceback.print_exc(file=sys.stdout)
wsdl_nameservice = self.request.uri.replace('/','').replace('?wsdl','').replace('?WSDL','')
fault = soapfault('Error in web service : {fault}'.format(fault=detail), wsdl_nameservice)
self.write(fault.getSoap().toxml())
self.finish()
Ceci est la méthode de poste à partir du gestionnaire de requêtes. C'est à partir du module de services web que j'utilise (donc pas mon code) mais j'ai ajouté le décorateur asynchrone et self.finish(). Tout ce qu'il fait est d'appeler l'opération correcte (comme dictée dans le SOAPAction de la demande).
class CountryService(soaphandler.SoapHandler):
@webservice(_params=GetCurrencyRequest, _returns=GetCurrencyResponse)
def get_currency(self, input):
result = db_query(input.country, 'currency')
get_currency_response = GetCurrencyResponse()
get_currency_response.currency = result
headers = None
return headers, get_currency_response
@webservice(_params=GetTempRequest, _returns=GetTempResponse)
def get_temp(self, input):
get_temp_response = GetTempResponse()
curr = self.make_curr_request(input.country)
get_temp_response.temp = curr
headers = None
return headers, get_temp_response
def make_curr_request(self, country):
soap_request = """<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:coun='CountryService'>
<soapenv:Header/>
<soapenv:Body>
<coun:GetCurrencyRequestget_currency>
<country>{0}</country>
</coun:GetCurrencyRequestget_currency>
</soapenv:Body>
</soapenv:Envelope>""".format(country)
headers = {'Content-Type': 'text/xml;charset=UTF-8', 'SOAPAction': '"http://localhost:8080/CountryService/get_currency"'}
r = requests.post('http://localhost:8080/CountryService', data=soap_request, headers=headers)
try:
tree = etree.fromstring(r.content)
currency = tree.xpath('//currency')
message = currency[0].text
except:
message = "Failure"
return message
Ce sont deux des opérations du service Web (get_currency & get_temp). Donc SOAPUI frappe get_temp, ce qui fait une requête SOAP à get_currency (via make_curr_request et le module de requêtes). Ensuite, les résultats devraient simplement revenir en arrière et être renvoyés à SOAPUI.
Le fonctionnement réel du service n'a aucun sens (retourner la monnaie lorsqu'on lui demande la température), mais j'essaie simplement de faire fonctionner la fonctionnalité et ce sont les opérations que j'ai.
Avez-vous essayé d'utiliser '@ tornado.web.asynchronous'? http://www.tornadoweb.org/documentation/web.html?highlight=async#tornado.web.asynchronous Veuillez poster du code si cela ne fonctionne pas, et je serai heureux de vous aider à résoudre votre problème. –
@StevePeak merci pour votre aide. Je l'ai utilisé pour la méthode post, mais je ne sais pas si je le fais correctement. Code pertinent ajouté maintenant. – johnharris85
Je vois quelques problèmes de syntaxe dans votre demande. Quelles sont les 'exceptions 'que vous voyez sur ce service (par exemple' NameError')? –