带有自定义绑定的 Savon

Savon with a custom binding

我有一项可爱的任务,就是与 Rails 一起处理大量的 SOAP api。 SOAP 服务具有三种不同的绑定; wsHttpBinding、wsHttpBinding with x509 和自定义绑定。我可以仅使用 wsHttpBinding 到达两个端点,但第三个端点需要用户名和密码,这不适用于此。由于证书的原因,我避免使用 x509,并且自定义绑定在 SoapUI 中工作得很好,但是对于 Savon,我得到以下错误。

The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).

我已经采用了用 Savon 生成的确切 XML 并将其放入 SoapUI 中并且它有效。

这会是一个有约束力的问题吗?有没有办法告诉它使用这个自定义绑定?

这是我在 App.config

中找到的自定义绑定
<bindings>
  <customBinding>
    <binding name="cust">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport />
    </binding>
    <binding name="cust1">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport />
    </binding>
    <binding name="cust2">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport />
    </binding>
  </customBinding>
</bindings>
<endpoint address="http://api.xyz.com/stuff.svc/cust"
    binding="customBinding" bindingConfiguration="cust" contract="stuff.Xstuff"
    name="cust" />

编辑 #1

这是我当前的客户端设置,希望对您有帮助。

@client = Savon.client(
      wsdl: 'http://api.xyz.com/stuff.svc?wsdl',
      wsse_auth: %w'username password',
      wsse_timestamp: true,
      raise_errors: false,
      log: true,
      log_level: :debug,
      soap_version: 2,
      pretty_print_xml: true,
      convert_request_keys_to: :none,
      use_wsa_headers: true,
      headers: {'Content-Type' => 'application/soap+xml; charset=utf-8'}

编辑 #2

我发现了问题。 Savon 没有像 SoapUI 那样在 Content-Type 中设置操作。感谢@RicardoPontual 建议尝试再次比较 Savon 和 SoapUI 请求,这让我仔细观察并注意到了问题。

headers: {'Content-Type' => 'application/soap+xml;charset=UTF-8;action="tempuri.org/stuf‌​f/set_table_stuff"'} 

你需要在Content-Typeheader中设置action="tempuri.org/stuf‌​f/set_table_stuff"',像这样:

@client = Savon.client(
      wsdl: 'http://api.xyz.com/stuff.svc?wsdl',
      wsse_auth: %w'username password',
      wsse_timestamp: true,
      raise_errors: false,
      log: true,
      log_level: :debug,
      soap_version: 2,
      pretty_print_xml: true,
      convert_request_keys_to: :none,
      use_wsa_headers: true,
      headers: {'Content-Type' => 'application/soap+xml; charset=UTF-8; action="tempuri.org/stuf‌​f/set_table_stuff";'}

根据我们在评论中讨论的内容,将 header 添加到您想要使用的操作的操作中可能会解决问题,如下所示:

@client = Savon.client(
      wsdl: 'http://api.xyz.com/stuff.svc?wsdl',
      wsse_auth: %w'username password',
      wsse_timestamp: true,
      raise_errors: false,
      log: true,
      log_level: :debug,
      soap_version: 2,
      pretty_print_xml: true,
      convert_request_keys_to: :none,
      use_wsa_headers: true,
      headers: {'Content-Type' => 'application/soap+xml;charset=UTF-8;action="tempuri.org/stuf‌​f/set_table_stuff"'}
      );