java 使用 spring webservice 发布的 service,由php使用SoapClient调用。
遇到有一个奇怪的现象,java调用发布的webservice,没有问题,使用工具SOAP UI调用,没有问题,
同样的php代码调用google的天气服务没问题,调用我们的wsdl就不行。
经过摸索调试,发现如下问题,以及解决的过程。
首先发布的wsdl如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://www.phpxiaoxin.com/doorway" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.phpxiaoxin.com/doorway" targetNamespace="http://www.phpxiaoxin.com/doorway">
<wsdl:types>
<s:schema xmlns:dw="http://www.phpxiaoxin.com/doorway" xmlns:s="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.phpxiaoxin.com/doorway">
<s:complexType name="Error">
<s:attribute name="Code" type="s:string" use="required"/>
<s:attribute name="Message" type="s:string" use="required"/>
</s:complexType>
<s:simpleType name="Status">
<s:restriction base="s:string">
<s:enumeration value="Successful"/>
<s:enumeration value="Failed"/>
</s:restriction>
</s:simpleType>
<s:complexType abstract="true" name="BaseRequest">
<s:attribute name="Token" type="s:string" use="required"/>
<s:attribute name="UserName" type="s:string" use="required"/>
<s:attribute name="Password" type="s:string" use="required"/>
</s:complexType>
<s:complexType abstract="true" name="BaseResponse">
<s:sequence>
<s:element minOccurs="0" name="Error" type="dw:Error"/>
</s:sequence>
<s:attribute name="Token" type="s:string" use="required"/>
<s:attribute name="Status" type="dw:Status" use="required"/>
</s:complexType>
<s:complexType name="StatusResponse">
<s:complexContent>
<s:extension base="dw:BaseResponse"/>
</s:complexContent>
</s:complexType>
<s:attribute name="RatePlanCode" type="s:string" use="required"/>
<s:attribute name="RoomTypeCode" type="s:string" use="required"/>
<s:attribute name="NumberOfUnits" type="s:int" use="required"/>
<s:attribute name="HotelCode" type="s:string" use="required"/>
<s:attribute name="DistributorReservationId" type="s:string" use="required"/>
</s:complexType>
<s:element name="PingRequest">
<s:complexType>
<s:complexContent>
<s:extension base="dw:BaseRequest">
<s:attribute name="Echo" type="s:string" use="required"/>
</s:extension>
</s:complexContent>
</s:complexType>
</s:element>
<s:element name="PingResponse">
<s:complexType>
<s:complexContent>
<s:extension base="dw:StatusResponse">
<s:attribute name="Echo" type="s:string" use="required"/>
</s:extension>
</s:complexContent>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="PingResponse">
<wsdl:part element="tns:PingResponse" name="PingResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="PingRequest">
<wsdl:part element="tns:PingRequest" name="PingRequest">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="Doorway">
<wsdl:operation name="Ping">
<wsdl:input message="tns:PingRequest" name="PingRequest">
</wsdl:input>
<wsdl:output message="tns:PingResponse" name="PingResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DoorwaySoap11" type="tns:Doorway">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Ping">
<soap:operation soapAction=""/>
<wsdl:input name="PingRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="PingResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HotelDoorwayService">
<wsdl:port binding="tns:DoorwaySoap11" name="DoorwaySoap11">
<soap:address location="/soap/doorway/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
其中定义了一个方法"Ping" 输入为PingRequest 和 PingResponse 其中PingRequest包含一个echo的属性,并集成一个BaseRequest的对象。
下面是使用php调用的代码:
<?php
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$wsdl="http://10.10.10.10:8888/doorway/soap/doorway/doorway.wsdl";
$soap=new SoapClient($wsdl, array( 'trace'=>true,'cache_wsdl'=>WSDL_CACHE_NONE, 'soap_version' => SOAP_1_1));
$method="Ping";
$params = array('Token'=>'E30ED3AA-65DE-48F9-BEA4-BA021B119625','UserName'=>'cccc','Password'=>'pppp', 'Echo'=>'hello');
try{
$result=$soap->$method($params);
}catch(Exception $e) {
echo "Exception: " . $e->getMessage();
}
//$result为stdClass类型,因此不能使用 echo $result的方式输出,会报错的。
echo $result->Echo;
?>
最初我们调用的时候获取到的错误是找不到Ping方法,这个后来不确定是如何解决的。
后来加了SoapClient 的调用参数WSDL_CACHE_NONE让soap调用的时候不缓存wsd,以避免服务器修改了wsdl无法及时更新。设置此参数后,每次调用,都会重新load wsdl文件,因此监控java的log,将会拿到一个get请求,起初我们以为是调用wsdl的请求,后来发现,他是拿wsdl的请求。
过了这关后,会遇到如下错误:Unable to parse URL
这个原因经过google之后发现问题出在wsdl上面:<soap:address location="/soap/doorway/"/>
这里有的wsdl会:<soap:address location=""/>
这种方式使用java调用是没有问题的,但是使用php调用就是不行。再加上错误的提示信息,可以理解为,SoapClient没有智能的解析这个location,因此无法调用到soap的地址(这里称之为地址,其实我也不知道是什么意思,要想搞懂的可以看wsdl的协议。)
按照往上介绍的方法,在SoapClient调用里面增加参数:location =>"http://www.phpxiaoxin.com/soap/doorway"
但这种方法显然是不太好的,更好的方法是在生成的wsdl中就将location参数直接设置成绝对的url地址不要是相对的,也不要是空。
另外需要注意一个细节就是soap_version,分为:SOAP_1_1,SOAP_1_2 这两者发送的header是不一样的,一个是:text/xml一个是soap/xml,有的时候不兼容,就会将请求拒绝掉。
最后还有一个问题就是组装调用方法参数:
所调用方法应该组装的参数,主要看方法对应的wsdl中的input,对于Ping方法来说,就是PingRequest。
pingRequest继承了一个BaseRequest,那么相当于PingRequest有:token、username、password,以及自身的echo,因此将这些属性直接组装成array塞进去就ok了。
这里没有实验过一个方法对应多个输入对象应该如何处理,大家可以自己去试。而对已简单到String类型的输入参数来说,我这边的param为:$params = array('arg0'=>"hello111");
不过我的这个我使用的是另外一个wsdl,其输入参数的wsdl为(使用spring+cxf+aegis数据绑定生成):
<xsd:complexType name="sayHello">
<xsd:sequence>
<xsd:element minOccurs="0" name="arg0" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
大家可以看看对应关系。是否能看出点什么规律。而对于复杂的对象,则可以层层的array进行嵌套。可以参开这个文章:PHP SOAP如何传入复杂对象
最后提醒一下:
php使用webservice的时候,需要确认开启了php_soap、php_curl的扩展(php.ini)
关于php的soap client 以及其option参数,可以参考官网:http://www.php.net/manual/en/soapclient.soapclient.php
使用php最好配置上xdebug以便可以调试,看到对象的值,相当明了,
SoapClient里面有发送的request的xml一看就知道是否有问题,以及问题出在哪里。
详情可以看一下xdebug等文章。
再就是php调用的时候我增加了try,catch,并且将exception输出,这样输出的结果似乎比直接跑异常要详细。
因此建议大家遇到问题的时候可以catch一下,以便能够看到详细的异常信息。
另外如果有对spring发布webservice以及spring+cxf发布webservice有问题的也可以找相关文章看一下。这里就不贴地址了。我也曾经介绍过cxf的。
总结一下,出错的缘由,由于本次webservice使用了手写xsd的方式,先手工写出了xsd,然后再生成的接口和对象,因此导致location设置不兼容。
参考:
unable-parse-url
nusoap-how-to-change-content-type-of-request
终于解决了PHP调用SOAP过程中的种种问题
分享一个xml在线格式化的工具:http://www.shell-tools.net/index.php?op=xml_format
分享到:
相关推荐
Java调用php的webservice: header("Content-Type:text/html;charset=UTF-8"); // require('lib/nusoap.php'); require_once("lib/nusoap.php"); $server = new soap_server(); $server->configureWSDL('...
里面是php调用java写的webservice的源码和说明,希望对大家有所帮助
2.1 用java建一个简单的工程sayHi,在里面编写一个简单的服务类sayHi,里面有一个函数sayHello. package Hi; publicclass sayHi { public String sayHello(String user,String weather) { return"Hi "+ user +". It'...
本篇文章主要是对PHP调用JAVA的WebService简单实例进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
内容概要:代码示例 C++调用WebService,Java调用WebService,C#调用WebService,Js调用WebService,VB调用WebService,ASP调用WebService,PHP调用WebService。 适用人群:WebService开发人员 使用场景:跨平台...
在WebService使用Md5和SHA1加密技术对用户密码进行加密处理,从而增加用户安全性。登陆判断同样通过Md5和SHA1加密密码然后和数据库经过加密密码进行比较来(它们可都是二进制滴哦!)验证用户是否存在 很好滴东西 ...
本学习笔记是记录学习PHP WebService和WebService在SugarCRM上如何应用的过程及相关知识点摘录。 学习如何实现PHP WebService,php及java中如何调用。
可以供c#调用,按理也可以给java的,不过没试过,搭环境太麻烦了。php运行环境 5.6
我个人比较推荐的做法是使用Java或PHP等开发接口或者编写WebService进行数据库的增删该查,然后Android调用接口或者WebService进行数据的交互。本文就给大家讲解在Android中如何调用远程服务器端提供的WebService。 ...
自己做的php webservice 接口json格式的 可改成xml格式.提供新手使用,说明文档很详细. 可 java asp.net 安卓 ios 调用php接口 非常简单的webservice接口代码 上手就能用
NULL 博文链接:https://corrinejtt.iteye.com/blog/851268
主要介绍了php中创建和调用webservice接口示例,包括webservice基本知识、webservice服务端例子、webservice客户端例子,需要的朋友可以参考下
基于axis2的java与php通信源码及说明文档,里面包括完整的源码和详细的说明文档,里面有java的服务端,java的客户端,和php的客户端。 由于上传不能超过20M,AxisTest里面的包需要朋友自己去下载,网上找axis2-1.5.1...
您可能感兴趣的文章:JAVA如何调用wsdl过程详解java WSDL接口webService实现方式PHP调用wsdl文件类型的接口代码分享解析利用wsdl.exe生成webservice代理类的详解在PHP中利用wsdl创建标准webservice的实现代码Java...
最近接触到一个银行接口的案子,临时需要用到axis2 webservice。自己现学现总结的一些东西,留给新手。少走弯路。 Axis2简介 ①采用名为 AXIOM(AXIs Object Model)的新核心 XML 处理模型,利用新的XML解析器提供...
php 5 apache 2.2 webservice 创建与配置 测试工具:wsCaller.jar (此文是给java程序调用的webservice) 提示:要运行wsCaller.jar 要选安装jdk 如果没有安装jdk 则wsCaller.jar 会以压缩包的形式显示 1 写webservice...
本文给出了一个java语言作为客户端,hessianphp语言写得web service的示例代码,和详细的说明。
ws-client客户端SDK,用于将安全性参数绑定到WebService客户端调度或端口 使用上述SDK单元测试示例 其他HTTP-SDK,用于其他语言的实现,例如PHP,Go和Node.js 从源代码构建 # 1. download sourcefrom Github (once ...
工行银企互联NC模式,非官方出品。本程序通过IIS+WebService,提供一个跨平台、跨语言的NetSafeClient中间服务层。...文档包含简要部署过程,验证方法以及相关代码(.NET、HTML文件、JAVA、PHP、Python)。