XML SOAP POST error, what am I doing wrong?
So I am trying to do an API call via a XML SOAP POST the error I am getting is: "Object reference not set to an instance of an object"
site = 'https://webservices.autotask.net/atservices/1.5/atws.asmx'
data = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<queryxml>
<entity>contact</entity>
<query>
<field>firstname<expression op="equals">George</expression>
</field>
</query>
</queryxml>
</soap:Body>
</soap:Envelope>"""
headers = {
'Content-Type': 'application/soap+xml; charset=utf-8',
'Host': 'webservices.autotask.net',
'Content-Type': 'text/xml; charset=utf-8',
'Content-Length': len(data),
'SOAPAction': "http://autotask.net/ATWS/v1_5/query"
}
site = 'https://webservices.autotask.net/atservices/1.5/atws.asmx'
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_ha开发者_StackOverflowndler.add_password(realm='webservices.autotask.net',
uri=site,
user='user,
passwd='pw')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
page = urllib2.urlopen(site)
print(data)
req = urllib2.Request(site, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()
print(the_page)
The auth works and I have done succesfull calls with this code, the only thing that is diffrent now is the data XML SOAP POST. I will try suds.
No Traceback only web server error:
Print out of the XML SOAP POST that I am sending:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<queryxml>
<entity>contact</entity>
<query>
<field>firstname<expression op="equals">George</expression>
</field>
</query>
</queryxml>
</soap:Body>
</soap:Envelope>
The response:
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><queryResponse xmlns="http://autotask.net/ATWS/v1_5/"><queryResult><ReturnCode>-1</ReturnCode><EntityResults /><EntityResultType /><Errors><ATWSError><Message>Object reference not set to an instance of an object.</Message></ATWSError><ATWSError><Message>Error reading in Query XML.</Message></ATWSError></Errors><EntityReturnInfoResults /></queryResult></queryResponse></soap:Body></soap:Envelope>
Any ideas?
George
Autotask has an ancient API on IIS 6... to deal with the microsoft crapstack you have to escape the XML you push over there as CDATA. Here's what worked for me as the soap body, within the
<ins0:query>
tags:
<ins0:sXML>
<![CDATA[<queryxml>
<entity>contact</entity>
<query>
<field>phone<expression op='equals'>#{phone}</expression></field>
</query>
</queryxml>]]>
</ins0:sXML>
George, here is an example of calling one of the test web services on webservicex.net
:
import suds
url = 'http://www.webservicex.net/stockquote.asmx?WSDL'
client = suds.client.Client(url=url)
print client.service.GetQuote('IBM')
<StockQuotes>
<Stock>
<Symbol>IBM</Symbol>
<Last>159.93</Last><Date>3/7/2011</Date><Time>4:00pm</Time>
<Change>-1.90</Change><Open>161.60</Open><High>162.98</High>
<Low>158.85</Low><Volume>5318064</Volume>
<MktCap>195.0B</MktCap><PreviousClose>161.83</PreviousClose>
<PercentageChange>-1.17%</PercentageChange>
<AnnRange>116.00 - 166.25</AnnRange>
<Earns>11.52</Earns><P-E>14.05</P-E>
<Name>International Bus</Name>
</Stock>
</StockQuotes>
You should be able to do HTTP basic authentication by passing in username and password on the constructor:
client = suds.client.Client(url=url, username='user', password='pw')
Good luck with suds!
The reply above indicating that their API is "dated" is a little bit of an understatement. That being said, the problem you are experiencing is because your XML is not formatted properly.
There is nothing crazy that they are expecting nor need from you other than a properly formatted XML body.
Eskim0 hand crafts a body for you, but the problem is that you probably don't see what he has actually done. He is crafting an "sXML" body within the larger SOAP request.
Most libraries (perl, python and php definitely all can do this) supply a method whereby you can pass in some queryxml and "sXML"ify it. This is the kind of thing you really shouldn't be trying to do by hand, as there are just too many details to keep track of.
So for example, in perl you'd do this:
$soap->query(SOAP::Data->value($query)->name('sXML'))
which would issue an sXML version of string $query to the query method at the soap endpoint.
精彩评论