9

我正在尝试访问我无法控制的 SOAP 服务。其中一个动作被称为ProcessMessage。我按照该示例生成了一个 SOAP 请求,但我收到一条错误消息,指出该操作不存在。我将问题追溯到信封主体的生成方式。

<env:Envelope ... ">
    <env:Header>
        <wsse:Security ... ">
            <wsse:UsernameToken ...">
                <wsse:Username>USER</wsse:Username>
                    <wsse:Nonce>658e702d5feff1777a6c741847239eb5d6d86e48</wsse:Nonce>
                    <wsu:Created>2010-02-18T02:05:25Z</wsu:Created>
                    <wsse:Password ... >password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </env:Header>
    <env:Body>
        <wsdl:ProcessMessage>
            <payload>
                ......
            </payload>
        </wsdl:ProcessMessage>
    </env:Body>
</env:Envelope>     

ProcessMessage标签应该是:

    <ProcessMessage xmlns="http://www.starstandards.org/webservices/2005/10/transport">

这就是示例 Java 应用程序生成它时的样子,并且它可以工作。该标记是我的 Ruby 应用程序生成的内容与示例 Java 应用程序之间的唯一区别。有没有办法摆脱"wsdl:"那个标签前面的命名空间并添加一个这样的属性。除此之外,有没有办法通过像身体其他部分一样作为字符串传递来强制不生成动作?

这是我的代码:

require 'rubygems'
require 'savon'
client = Savon::Client.new "https://gmservices.pp.gm.com/ProcessMessage?wsdl"

response = client.process_message! do | soap, wsse |
wsse.username = "USER"
wsse.password = "password"
soap.namespace = "http://www.starstandards.org/webservices/2005/10/transport" #makes no difference
soap.action = "ProcessMessage" #makes no difference
soap.input = "ProcessMessage" #makes no difference

#my body at this point is jsut one big xml string

soap.body = "<payload>...</payload>" 
# putting <ProccessMessage> tag here doesn't help as it just creates a duplicate tag in the body, since Savon keeps interjecting  <wsdl:ProcessMessage> tag.

  end

我尝试了 handsoap,但它不支持 HTTPS 并且令人困惑。我尝试了soap4r,但它比handsoap 更令人困惑。

4

4 回答 4

10

您需要将一个数组传递给soap.input,其中的第二个元素是一个包含命名空间详细信息的散列。

soap.input = [ 
  "ProcessMessage", 
  {"xmlns" => "http://www.starstandards.org/webservices/2005/10/transport"}
]

这应该确保您最终将名称空间声明作为主元素的属性。

您可能还会在元素之前得到一个命名空间声明,就像这样

<env:Body>
    <wsdl:ProcessMessage xmlns="........." >
        <payload>
            ......
        </payload>
    </wsdl:ProcessMessage>
</env:Body>

但这对我来说不是问题,问题在于缺少名称空间属性,而不是元素之前存在名称空间。

于 2010-03-16T09:20:06.173 回答
7

对于我的 Web 服务,我需要摆脱"wsdl"史蒂夫解决方案之上的命名空间。

用 Savon 0.9.6 测试:

client = Savon::Client.new "https://example.com/webservice/account.asmx?WSDL"
response = client.request "GetAccount" do
  # Gotcha 1: set default namespace for body elements
  soap.input = ["GetAccount", {"xmlns" => "https://example.com/webservice/"}]
  soap.body = {
    "AccountID" => 1234
  }
  # Gotcha 2: get rid of namespace declaration of body elements
  soap.element_form_default = :unqualified
  # Gotcha 3: set SOAPAction different from default
  http.headers["SOAPAction"] = '"https://example.com/webservice/GetAccount"'
end
于 2011-08-06T22:26:01.037 回答
4

史蒂夫,你看到 wsdl: 在 ProcessMessage 标记前面了吗?- 我认为这是唯一让我失望的事情,但事实并非如此(顺便说一句,它很难在第 160 行的 Savon lib 的 soap.rb 中设置)。即使我没有在soap.namespaces 中对其进行spacify - 它也很难生成并附加在最终的xml 中。我的服务不允许这样做。

虽然生成的 xml 是一个有效的 xml——但我试图与之交谈的服务的要求并不完整。即:在生成的xml中,

<?xml version="1.0" encoding="UTF-8"?>

标记丢失,另外,我需要标题中的 PayloadManifest,加上我的 wsse: 标记中需要 wsu:created 和 wsu:expires,但它们没有实现,等等等等。我的情况。然而,soap 有一个私有方法 = xml_body。to_xml 方法中的soap lib也在生成它自己的xml之前检查是否已经设置了@xml_body。所以我最终稍微修改了肥皂的行为。通过使soap.xml_body = 可公开访问。所以我能够做到:

response = client.process_message! do |soap| 
soap.action = "http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage"
soap.xml_body = "MY XML STRING GENERATED ELSEWHERE GOES HERE"
end

终于奏效了!!!!

我会向 rubii 建议这个 - 如果这个选项可用,这将解决很多罕见的情况 - 人们可以生成他们的自定义 xml 并使用其余的 savon lib。

于 2010-03-16T20:39:12.030 回答
0

我花了几个小时试图找到一个解决方案来摆脱:

<wsdl:ProcessMessage>
</wsdl:ProcessMessage>

这就是我想要的:

client = Savon.client(
 :no_message_tag => true
)

在 Savon 2 中测试。

于 2020-04-23T02:27:56.870 回答