How to make a SOAP request using SOAPpy?

I am trying to call a method using a SOAP request using SOAPpy in Python 2.7. The method is called GetCursOnDate and returns exchange rates. It takes a date parameter.

I am using the following code:

 from SOAPpy import SOAPProxy import datetime date=datetime.datetime.now() namespace ="http://web.cbr.ru/" url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" server = SOAPProxy(url,namespace) print (date) server.GetCursOnDate(date) 

But I will return to the error:

Soap with an error: Client: the server did not recognize the value of the HTTP header SOAPAction: GetCursOnDate.

Why am I getting this error?

+6
source share
2 answers

By default, SOAPpy uses the method name as the value of the HTTP SOAPAction header. If you run the following code, you will see the value in the debug output:

 from SOAPpy import SOAPProxy from datetime import datetime input = datetime.now() namespace = "http://web.cbr.ru/" url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" proxy = SOAPProxy(url, namespace) proxy.config.debug = 1 proxy.GetCursOnDate(input) 

Debugging shows this:

 *** Outgoing HTTP headers *************************** POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.0 Host: www.cbr.ru User-agent: SOAPpy 0.12.5 (http://pywebsvcs.sf.net) Content-type: text/xml; charset=UTF-8 Content-length: 406 SOAPAction: "GetCursOnDate" ***************************************************** 

But the service expects a different value ( http://web.cbr.ru/GetCursOnDate ), which you can set on the proxy with an additional parameter. The following code clears the error:

 from SOAPpy import SOAPProxy from datetime import datetime input = datetime.now() namespace = "http://web.cbr.ru/" url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" soapaction = "http://web.cbr.ru/GetCursOnDate" proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction) proxy.config.debug = 1 proxy.GetCursOnDate(input) 

Debugging will now show this:

 *** Outgoing HTTP headers *************************** POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.0 Host: www.cbr.ru User-agent: SOAPpy 0.12.5 (http://pywebsvcs.sf.net) Content-type: text/xml; charset=UTF-8 Content-length: 406 SOAPAction: "http://web.cbr.ru/GetCursOnDate" ***************************************************** 

But, despite the fact that this particular error has disappeared, the call will not work. . Since you will come back with questions, I thought that I would save us from messaging and write the sequel directly. I mentioned my disappointment with Python SOAP support on another occasion . For this post, I add all the details here as a link to myself and, hopefully, as help to other users. So here it is ...

The call will not work, because by default SOAPpy uses ordered parameters for the call. They are called v1 , v2 , v3 , etc. (See the MethodParameterNaming.txt file inside the SOAPpy download for more information). Your SOAP message will look like this:

 <SOAP-ENV:Body> <ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1"> <v1> </v1> </ns1:GetCursOnDate> </SOAP-ENV:Body> 

This particular web service expects a parameter named On_date , not v1 . You can try to fix this using named parameters:

 from SOAPpy import SOAPProxy from datetime import datetime input = datetime.now() namespace = "http://web.cbr.ru/" url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" soapaction = "http://web.cbr.ru/GetCursOnDate" proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction) proxy.config.debug = 1 proxy.GetCursOnDate(On_date = input) 

Your message now looks like this:

 <SOAP-ENV:Body> <ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1"> <On_date> </On_date> </ns1:GetCursOnDate> </SOAP-ENV:Body> 

I think the date value is missing because the proxy has a problem with datetime objects. I did not actually check what was connected with this, because there is another problem with this message: the web service is expecting <ns1:On_date> not <On_date> .

Here SOAPpy has some problems with namespaces. Using SOAPpy source code, you cannot change namespaces. It looks like with most Python SOAP libraries you can get the desired behavior by changing the code, which I did. I changed the SOAPBuilder.py file in some places where namespaces and tags were processed. See Source file here and modified here .

These changes allow me to use the SOAPpy Type for finer control over the message:

 from SOAPpy import SOAPProxy from SOAPpy import Types namespace = "http://web.cbr.ru/" url = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx" soapaction = "http://web.cbr.ru/GetCursOnDate" input = Types.dateType(name = (namespace, "On_date")) proxy = SOAPProxy(url, namespace = namespace, soapaction = soapaction) proxy.config.debug = 1 proxy.GetCursOnDate(input) 

Now I get the result I was looking for:

 <SOAP-ENV:Body> <ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1"> <ns1:On_date xsi:type="xsd:date">2013-11-02Z</ns1:On_date> </ns1:GetCursOnDate> </SOAP-ENV:Body> 

The server returns data for the above request.

But even the code above can be improved. Note that I set SOAPAction in the proxy for one specific operation: GetCursOnDate . If I want to use it with a different operation, I need a different proxy server, or I need to change it. Using WSDL.Proxy , you get this automatically from WSDL (it provides a SOAPProxy wrapper that parses method names, namespaces, and SOAPAction from the WSDL web service).

But even if it processes SOAPAction automatically, it does not take the namespace for the method. Therefore, I changed the WSDL.py file. The original version is here , the modified file is here . The new client code now looks like this:

 from SOAPpy import WSDL from SOAPpy import Types # you can download this and use it locally for better performance wsdl = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl" namespace = "http://web.cbr.ru/" input = Types.dateType(name = (namespace, "On_date")) proxy = WSDL.Proxy(wsdl, namespace = namespace) proxy.soapproxy.config.debug = 1 proxy.GetCursOnDate(input) 

In the above examples, I used Python 2.6.6, SOAPpy 0.12.5, fpconst 0.7.2, and wstools 0.4.3. For others, I consider YMMV depending on the version or specific web service that you are calling. In conclusion, I also want to mention that if you do a Google search, you'll notice that most people recommend SUDS instead of SOAPpy as a SOAP client , so maybe look at that too. Good luck

+12
source

it looks like targetNamespace is being ignored, but you can set a namespace for each operation, which works fine with soappy.

 <operation name="createCall"> <soap:operation soapAction=""/> <input> <soap:body use="literal" namespace="http://create.service/"/> </input> <output> <soap:body use="literal" namespace="http://create.service/"/> </output> </operation> 

of course you should use your namespace instead of http://create.service/

0
source

Source: https://habr.com/ru/post/957126/


All Articles