Java 上的 SOAP 请求无效,但在 PHP 上有效

SOAP request on Java not working, but does on PHP

我一直在尝试查找有关此问题的信息,但似乎找不到与我的问题完全相关的任何信息。

当我使用 PHP class SoapClient 进行 soap 调用时,请求工作正常。但是当我尝试在 Java 上做同样的事情时,我得到一个异常,说 URL 不接受 POST,我看到有人在 PHP 上构建 Soap 调用] 使用 Curl,使用 POST,但我真的不知道 SoapClient 做了什么。

无论如何,这是 PHP 代码:

$url    = 'https://mail.myzimbra.mx/service/wsdl/ZimbraAdminService.wsdl';
$soap_client = new SoapClient($url, array("soap_version" => SOAP_1_1,"trace" => 1));

$ns = 'urn:zimbra';

$headerbody = array('context' => '');

//Create Soap Header.       
$header = new SOAPHeader($ns, 'RequestorCredentials', $headerbody);       

//set the Headers of Soap Client.
$soap_client->__setSoapHeaders($header);

$AuthRequestObjectXML  = '<AuthRequest xmlns="urn:zimbraAdmin" password="password">
        <account by="adminName">user@zimbra.mx</account>
    </AuthRequest>';


$AuthRequestObject  = new SoapVar($AuthRequestObjectXML,XSD_ANYXML);

$objResponse = $soap_client->__soapCall(
        'AuthRequest',
       array($AuthRequestObject)
   );

$lastrequest = $soap_client->__getLastRequest();


$token = $objResponse->authToken;

它并不花哨,但它完成了工作。

现在,在 java(我已经尝试了几次,但这是我最后一次尝试):

String send = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">" +
              "<soap:Header xmlns=\"urn:zimbra\">" +
              "<context></context>" +
              "</soap:Header>" +
              "<soap:Body>" +
              "<AuthRequest xmlns=\"urn:zimbraAdmin\" password=\""+ ZIMBRA_ADMIN_PASSWORD +"\">" +
              "<account by=\"adminName\">"+ ZIMBRA_ADMIN_ACCOUNT +"</account>" +
              "</AuthRequest>" +
              "</soap:Body>" +
              "</soap:Envelope>";

      SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();
      SOAPConnection connection = sfc.createConnection();
      InputStream is = new ByteArrayInputStream(send.getBytes());
      SOAPMessage request = MessageFactory.newInstance().createMessage(null, is);

      request.writeTo(System.out); //Here it prints my envelop, which is formed just like the PHP one.

      URL endpoint = new URL(URL_ZIMBRA_ADMIN_WSDL);
      SOAPMessage response = connection.call(request, endpoint);

变量确实匹配PHP值,它们完全相同,我已经验证了一百次。

但是马蹄莲需要几秒钟,我猜大概是 20 秒,然后我得到了

com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (400HTTP method POST is not supported by this URL
    at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:149)
    at com.project.services.ZimbraService.getToken(ZimbraService.java:79)

*more stuff*

CAUSE:

com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (400HTTP method POST is not supported by this URL
    at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:264)
    at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:145)

我尝试了几种方法,比如将协议更改为 SOAPConstants。SOAP_1_2_PROTOCOL,因此请求 header 内容类型更改为 application/soap+xml,但没有任何效果似乎工作,我总是得到 POST not allowed by URL 异常。还尝试了一些我读到的关于更改 URL 以删除 wsdl 文件部分的其他线程,但没有成功。

那么,如果它适用于 PHP,为什么它不适用于 java?我在同一台机器上 运行 这两个脚本。

PHP 的 SoapClient 有所谓的 "WSDL mode",当您为它提供 WSDL 的 URL 时,它会下载该 WSDL,并提取来自 WSDL 的真正终点 URL

Java的SOAPConnection没有"WSDL mode",所以需要给call()方法提供真正的终点URL,不是 WSDL URL.

如果不知道真正的终点URL,就跟SoapClient一样,自己下载WSDL看看。终点URL会在最后

来自example WSDL

  ...

  <service name="EndorsementSearchService">
    <documentation>snowboarding-info.com Endorsement Service</documentation> 
    <port name="GetEndorsingBoarderPort"
          binding="es:EndorsementSearchSoapBinding">
      <soap:address location="http://www.snowboard-info.com/EndorsementSearch"/>
    </port>
  </service>

</definitions>

这里真正的终点URL是:http://www.snowboard-info.com/EndorsementSearch