2013-10-31 74 views
6

我想通過在Python 2.7上使用SOAPpy調用一個使用SOAP請求的方法。該方法被稱爲GetCursOnDate並返回匯率。它需要一個日期參數。如何使用SOAPpy進行SOAP請求?

我用下面的代碼:

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) 

但我回來了一個錯誤:

Fault soap:Client: Server did not recognize the value of HTTP Header SOAPAction: GetCursOnDate.

爲什麼會出現這個錯誤?

回答

12

默認情況下,SOAPpy使用方法名稱作爲HTTP SOAPAction標頭的值。如果您運行下面的代碼,你會看到在調試輸出值:

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) 

調試表明這一點:

*** 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" 
***************************************************** 

但服務需要另一個值(http://web.cbr.ru/GetCursOnDate),您可以在設置代理與一個額外的參數。 下面的代碼清除錯誤:

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) 

調試現在將顯示此:

*** 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" 
***************************************************** 

但是,雖然特定故障消失了,電話將無法工作。因爲你會回來的問題,我想我會留下一些消息交流,直接寫續集。我提到了我對Python的SOAP支持on another occasion的失望。對於這篇文章,我在這裏添加所有的細節作爲對我自己的參考,並希望作爲其他用戶的幫助。所以在這裏...

該調用將不起作用,因爲默認情況下,SOAPpy使用有序參數進行調用。它們被稱爲v1v2,v3等(請參閱SOAPpy下載中的MethodParameterNaming.txt文件以獲取更多詳細信息)。您的SOAP消息看起來就像這樣:

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

這個特定的Web服務期待一個名爲On_date,不v1參數。你可以嘗試使用命名參數來解決這個問題:

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) 

你的消息現在看起來是這樣的:

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

我想日期的值丟失,因爲代理與datetime對象的問題。我沒有實際檢查以確定問題所在,因爲此消息存在另一個問題:Web服務期望<ns1:On_date>不是<On_date>

這是SOAPpy在命名空間中遇到的一些問題。使用原始的SOAPpy源代碼,您不能更改命名空間。看起來,對於大多數Python的SOAP庫,您只能通過調整代碼來獲得所需的行爲,這正是我所做的。我在某些處理名稱空間和標記前綴的地方更改了SOAPBuilder.py文件。請參閱原始文件here和更改的here

這些變化讓我用一個SOAPpy的類型用於在消息的更精細的控制:

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) 

現在我得到我一直在尋找的結果:

<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> 

服務器返回關於上述請求的數據。

但是即使是上面的代碼也可以改進。請注意,我將SOAPAction設置爲代理服務器上的一項特定操作:GetCursOnDate。如果我想用另一個操作,我需要另一個代理或我需要修改這個。通過使用WSDL.Proxy,您可以從WSDL中自動獲取該文件(它提供了一個SOAPProxy包裝器,用於解析來自Web服務的WSDL的方法名稱,名稱空間和SOAPAction)。

但即使這會自動處理SOAPAction,它不會爲該方法拾取名稱空間。所以我調整了WSDL.py文件。原始版本是here,更改的文件是here。新的客戶端的代碼現在看起來是這樣的:

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) 

對於上面我使用的Python 2.6.6,SOAPpy的0.12.5,fpconst 0.7.2和wstools 0.4.3的例子。對於其他人,我認爲YMMV取決於您所調用的版本或特定的Web服務。總之我還想提一提,如果你在Google上搜索,你會發現大多數人推薦使用SUDS而不是SOAPpy作爲SOAP客戶端,所以也許可以看一下。祝你好運!

0

它看起來像targetNamespace被忽略,但你可以設置一個命名空間每個操作什麼與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> 

當然你應該使用的,而不是你的名字空間http://create.service/