python - 如何使用 SOAPpy 发出 SOAP 请求?

标签 python web-services soap soap-client soappy

我正在尝试通过在 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 did not recognize the value of HTTP Header SOAPAction: GetCursOnDate.

为什么会出现此错误?

最佳答案

默认情况下,SOAPpy 使用方法名称作为 HTTP SOAPAction 的值 header 。如果运行以下代码,您将在调试输出中看到该值:

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 使用有序参数进行调用。他们被称为v1 , v2 , 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 在 namespace 方面存在一些问题的地方。使用原始的 SOAPpy 源代码,您无法更改 namespace 。似乎对于大多数 Python 的 SOAP 库,您只能通过调整代码来获得所需的行为,这就是我所做的。我改变了 SOAPBuilder.py在处理 namespace 和标记前缀的某些地方创建文件。见原文件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 中解析方法名称、 namespace 和 SOAPAction s)。

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

关于python - 如何使用 SOAPpy 发出 SOAP 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19708597/

相关文章:

c# - .NET soap 客户端调用

python - 无法将图像二进制文件添加到多部分/表单数据中

python - Numpy 子矩阵运算

.net - Web 服务中的异常(exception)

c# - 使用 Windows Phone 8 发送 SOAP 请求

python - SUDS:在 Client.service 方法中传递数组参数:GAE Python

python - 使用 pySerial 的 AT cmd 响应

python - 如何将递归应用于算法?

xml - 佣金明细服务 (REST)

java - WebService 类中的 Spring Autowired 不起作用