2010-03-05 1 views
15

Так что я пытаюсь получить доступ к этому api https://www.clarityaccounting.com/api-docs/ с помощью SUDS. Вот код, который должен работать:Можете ли вы помочь мне решить эту проблему с SUDS/SOAP?

from suds.client import Client 
client = Client('https://www.clarityaccounting.com/api/v1?wsdl') 
token = client.service.doLogin('demo', 'demo', 'www.kashoo.com', 'en_US', 300000) 

Но я получаю эту ошибку:

WebFault: Server raised fault: 'No such operation: (HTTP GET PATH_INFO: /api/v1)' 

Их парень поддержка говорит о том, что запрос должен выглядеть следующим образом:

<SOAP-ENV:Envelope 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:api="http://api.service.books/"> 
    <SOAP-ENV:Body> 
    <api:doLogin> 
     <username>demo</username> 
     <password>demo</password> 
     <siteName>www.kashoo.com</siteName> 
     <locale>en_US</locale> 
     <duration>300000</duration> 
    </api:doLogin> 
    </SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

Но Suds» выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?> 
<SOAP-ENV:Envelope 
xmlns:ns0="http://api.service.books/" 
xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
    <SOAP-ENV:Header/> 
    <ns1:Body> 
     <ns0:doLogin> 
     <username>demo</username> 
     <password>demo</password> 
     <siteName>www.kashoo.com</siteName> 
     <locale>en_US</locale> 
     <duration>300000</duration> 
     </ns0:doLogin> 
    </ns1:Body> 
</SOAP-ENV:Envelope> 

Я настоящий SOAP и SUDS новичок, но я слышал, что SUDS - лучшая библиотека SOAP, которую можно использовать отсюда: What SOAP client libraries exist for Python, and where is the documentation for them?

Так что мой вопрос - это просто то, что являются важными частями, которые отличаются и которые делают запрос неудачным и как я могу настроить SUDS для отправки правильно отформатированного запроса?

ответ

35

На первый взгляд похоже, что проблема связана с SSL. Вы получаете доступ к URL-адресу https, а обработчик транспорта для suds.client говорит по умолчанию по умолчанию.

Проблема
Если вы посмотрите на нижней части WSDL он с указанием местоположения по умолчанию, как http://www.clarityaccounting.com/api/v1, который является HTTP URL, но WSDL является SSL.

<wsdl:service name="v1"> 
    <wsdl:port binding="tns:v1SoapBinding" name="BooksApiV1Port"> 
     <soap:address location="http://www.clarityaccounting.com/api/v1"/> 
    </wsdl:port> 
</wsdl:service> 

Если вы делаете HTTP GET на этот URL, вы получите сообщение об ошибке вы получили:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Body> 
     <soap:Fault> 
      <faultcode>soap:Server</faultcode> 
      <faultstring>No such operation: (HTTP GET PATH_INFO: /api/v1)</faultstring> 
     </soap:Fault> 
    </soap:Body> 
</soap:Envelope> 

Решение
Чтобы это исправить, необходимо переопределить местоположение по умолчанию, когда вы вызовите Client конструктор, чтобы сделать его придерживаться https:

>>> url 
'https://www.clarityaccounting.com/api/v1?wsdl' 
>>> client = Client(url, location='https://www.clarityaccounting.com/api/v1') 
>>> token = client.service.doLogin('demo', 'demo', 'www.kashoo.com', 'en_US', 300000) 
>>> token 
(authToken){ 
    authenticationCode = "ObaicdMJZY6UM8xZ2wzGjicT0jQ=" 
    expiryDate = 2010-03-05 12:31:41.000698 
    locale = "en_US" 
    myUserId = 4163 
    site = "www.kashoo.com" 
} 

Победа!

Советник для будущих целей отладки: включите полную регистрацию отладки. SUDS использует стандартную библиотеку logging, поэтому она дает вам большой контроль. Таким образом, я провернул все это до DEBUG:

import logging 
logging.basicConfig(level=logging.INFO) 
logging.getLogger('suds.client').setLevel(logging.DEBUG) 
logging.getLogger('suds.transport').setLevel(logging.DEBUG) 
logging.getLogger('suds.xsd.schema').setLevel(logging.DEBUG) 
logging.getLogger('suds.wsdl').setLevel(logging.DEBUG) 

Это то, что помогло мне сузить ее, потому что это было ясно говоря, что это посылает через HTTP:

DEBUG:suds.transport.http:sending: 
URL:http://www.clarityaccounting.com/api/v1 
(xml output omitted) 

А потом сказал так, как ответ скважина:

DEBUG:suds.client:http failed: 
+1

Рад помочь! Это была забавная проблема, чтобы выяснить в пятницу днем. – jathanism

+3

+1 Приятное касание, чтобы включить отладочную помощь – Draemon

+0

Спасибо! Я просто испытывал такую ​​же проблему с другим веб-сервисом, но с тем же вопросом https/http. Я не мог найти, как настроить клиента на использование https, хотя WSDL сказал использовать http. –

1

Не должно быть проблем, связанных с подключением к службе через HTTPS. Я использую пенообразование, чтобы сделать то же самое. Я пробовал несколько подходов к вашему WSDL-файлу (а не самому эксперту) и столкнулся с той же ошибкой. То, что вы должны делать, как практика с пеной, но использует метод , например.

login = client.factory.create('doLogin') 
login.username = 'username' 
etc... 

Где что-либо, отправленное функции create, является одним из типов, определенных в файле WSDL. Если вы создаете этот тип в оболочке, вы можете запустить «login для печати», чтобы увидеть его дополнительные свойства.

Надеюсь, это, по крайней мере, говорит вам, где проблема не с (HTTPS). Кроме того, я заметил, что заголовки soapAction не установлены в файле WSDL, не уверены, как бездействуют запросы или службы.

+0

Как вы можете видеть в моем пересмотренном ответе, проблема заключалась не в подключении через https, а при несогласованности в WSDL, обслуживаемом по https, тем временем указывая SOAP-вызовы на http. Я предполагаю, что причиной того, что они имеют службу, настроенную для перенаправления входящих URL-адресов с http на https, является источником проблемы. Все, что мы действительно сделали, это сработало. – jathanism

+0

Отладка для победы zee! – bennylope

1

Использование suds-jurko https://pypi.python.org/pypi/suds-jurko, который является поддерживаемой вилкой пены. Вы можете передать опцию __inject, в которой вы можете передать ей необработанный xml, который хотите отправить.

from suds.client import Client 

username, password, sitename, locale, duration = 'demo', 'demo', 'www.kashoo.com', 'en_US', 300000 

raw_xml = """<SOAP-ENV:Envelope 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:api="http://api.service.books/"> 
    <SOAP-ENV:Body> 
    <api:doLogin> 
     <username>{0}</username> 
     <password>{1}</password> 
     <siteName>{2}</siteName> 
     <locale>{3}</locale> 
     <duration>{4}</duration> 
    </api:doLogin> 
    </SOAP-ENV:Body> 
</SOAP-ENV:Envelope>""".format(username, password, sitename, locale, duration) 

client = Client(url, location) 
result = client.service.doLogin(__inject={'msg':raw_xml}) 

Я чувствую, что должен документировать все способы, которые можно инспектировать Необработанный мыло, пена создает здесь.

  1. Использование флага nosend при конструировании клиента. Обратите внимание, что с флагом, установленным на True, пена будет просто генерировать мыло, но не отправлять его.

    client =Client(url, nosend=True)
    res = client.service.example()
    print res.envelope #prints Необработанные SOAP

  2. с использованием протоколирования. Здесь мы только регистрируем suds.transport.http, поэтому он будет выводить только то, что отправлено/получено.

    import logging
    import sys
    handler = logging.StreamHandler(sys.stderr)
    logger = logging.getLogger('suds.transport.http')
    logger.setLevel(logging.DEBUG), handler.setLevel(logging.DEBUG)
    logger.addHandler(handler)

  3. Использование MessagePlugin

    from suds.plugin import MessagePlugin
    class MyPlugin(MessagePlugin):
    def marshalled(self, context):
    #import pdb; pdb.set_trace()
    print context.envelope.str()

    client = Client(url, plugins=[MyPlugin()])

не только в MessagePlugin даст вам возможность проверять мыло порождена, но вы также можете изменить его перед отправкой, See->https://jortel.fedorapeople.org/suds/doc/suds.plugin.MessagePlugin-class.html

Смежные вопросы