如何使用SOAPpy发出SOAP请求?

Leo*_*eo 6 python soap web-services soappy soap-client

我试图通过在Python 2.7上使用SOAPpy来调用使用SOAP请求的方法.该方法被调用GetCursOnDate并返回汇率.它需要一个日期参数.

我正在使用以下代码:

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)
Run Code Online (Sandbox Code Playgroud)

但是我收到了一个错误:

Fault soap:Client:Server无法识别HTTP Header SOAPAction的值:GetCursOnDate.

为什么我会收到此错误?

Bog*_*dan 13

默认情况下,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)
Run Code Online (Sandbox Code Playgroud)

调试显示:

*** 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"
*****************************************************
Run Code Online (Sandbox Code Playgroud)

但是服务期望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)
Run Code Online (Sandbox Code Playgroud)

调试现在将显示:

*** 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"
*****************************************************
Run Code Online (Sandbox Code Playgroud)

但是,虽然这个特定的故障已经消失,但呼叫将无效.因为你会回答问题,我想我会给我们留言,并直接写下续集.我在另一个场合提到了我对Python的SOAP支持的失望.对于这篇文章,我在这里添加所有细节作为对自己的参考,并希望作为其他用户的帮助.所以这里......

该调用无效,因为默认情况下,SOAPpy使用有序参数进行调用.他们被称为v1,v2,v3等(见MethodParameterNaming.txt的SOAPpy的下载文件,里面有详细介绍).您的SOAP消息将如下所示:

<SOAP-ENV:Body>
    <ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1">
        <v1>
        </v1>
    </ns1:GetCursOnDate>
</SOAP-ENV:Body>
Run Code Online (Sandbox Code Playgroud)

这个特定的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)
Run Code Online (Sandbox Code Playgroud)

您的消息现在看起来像这样:

<SOAP-ENV:Body>
    <ns1:GetCursOnDate xmlns:ns1="http://web.cbr.ru/" SOAP-ENC:root="1">
       <On_date>
       </On_date>
    </ns1:GetCursOnDate>
</SOAP-ENV:Body>
Run Code Online (Sandbox Code Playgroud)

我认为日期的值缺失,因为代理有datetime对象的问题.我实际上没有检查以查看问题是什么,因为此消息还有另一个问题:Web服务<ns1:On_date>不期望<On_date>.

这就是SOAPpy在命名空间方面存在一些问题的地方.使用原始的SOAPpy源代码,您无法更改名称空间.这似乎与大多数Python的SOAP库,你可以通过调整代码,这是我做的只是得到你想要的行为.我SOAPBuilder.py在一些处理名称空间和标记前缀的地方更改了文件.看到原来的文件在这里和一个改变了这里.

这些更改允许我使用SOAPpy Type来更好地控制消息:

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)
Run Code Online (Sandbox Code Playgroud)

现在我得到了我正在寻找的结果:

<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>
Run Code Online (Sandbox Code Playgroud)

服务器返回上述请求的数据.

但即使上面的代码也可以改进.请注意,我正在SOAPAction为一个特定操作设置代理:GetCursOnDate.如果我想在另一个操作中使用它,我需要另一个代理,或者我需要修改这个.通过使用WSDL.Proxy你从WSDL(它提供了一个自动获得此SOAPProxy,它解析方法名称,命名空间和包装SOAPAction从Web服务的WSDL S).

但即使SOAPAction它自动处理它也不会获取该方法的命名空间.所以我调整了WSDL.py文件.原始版本在这里,更改文件在这里.新的客户端代码现在看起来像这样:

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)
Run Code Online (Sandbox Code Playgroud)

对于上面我用的Python 2.6.6,SOAPpy的0.12.5的例子中,fpconst 0.7.2和wstools 0.4.3.对于其他人,我认为YMMV取决于您呼叫的版本或特定Web服务.最后,我也想提一提,如果你在谷歌做搜索,你会发现,大多数人建议肥皂水代替SOAPpy的作为SOAP客户端,所以也许看看这一点.祝好运!