【问题标题】:How to make a SOAP request by using SOAPpy?如何使用 SOAPpy 发出 SOAP 请求?
【发布时间】:2013-10-31 14:00:18
【问题描述】:

我正在尝试通过在 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)

但我得到一个错误:

Fault soap:Client: Server 没有识别 HTTP Header SOAPAction: GetCursOnDate 的值。

为什么会出现这个错误?

【问题讨论】:

    标签: python web-services soap soap-client soappy


    【解决方案1】:

    默认情况下,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 使用有序参数进行调用。它们被称为v1v2v3 等(有关详细信息,请参阅 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 服务需要&lt;ns1:On_date&gt; 而不是&lt;On_date&gt;

    这就是 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>
    

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

    但即使是上面的代码也可以改进。请注意,我在代理上为一项特定操作设置了SOAPActionGetCursOnDate。如果我想将它与另一个操作一起使用,我需要另一个代理,或者我需要修改这个。通过使用WSDL.Proxy,您可以从 WSDL 中自动获取此信息(它提供了一个 SOAPProxy 包装器,用于解析来自 Web 服务的 WSDL 的方法名称、命名空间和 SOAPActions)。

    但即使这会自动处理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 客户端,所以也许也可以看看。祝你好运!

    【讨论】:

      【解决方案2】:

      看起来 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/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-25
        • 1970-01-01
        相关资源
        最近更新 更多