作者: 吴俊杰

web service这项技术暂不说它有多落伍,但是项目中用到了,没法逃避!
    xml和json各有各的好处,但是JSON无疑是当今数据交互的主流了。客户soap服务器端用的是 java+xfire开发的,而我不懂java,可是我和客户的程序有数据交互,起初我推荐用json数据格式,但是客户执意要用web service。拗不过,只有研究 php的soap了。
    事实证明:这可不是一件容易的事情,web service虽号称 “跨平台与开发语言无关” ,实则是机关重重,陷阱遍布!网上的参考资料凌乱不堪,去糟存精也绝非易事,调通这个确实是走了不少弯路,在没有人指导的情况下,一直在网上search,一路之艰辛实属不易!下面就就记录一下php和java+xfire互为 web service服务器之间的一些细节,防止再次用到的时候,又走弯路,浪费时间。

1)普及知识:php的soap类库
参考:http://www.cnblogs.com/chance1/archive/2009/04/08/1431949.html

php有两个扩展可以实现web service,一个是NuSoap,另一个是php官方的soap扩展,由于soap是官方的,所以我们这里以soap来实现web service.由于默认是没有打开soap扩展的,所以自己先看一下soap扩展有没有打开。

在soap编写web service的过程中主要用到了SoapClient,SoapServer,SoapFault三个类。

SoapClient类
这个类用来使用Web services。SoapClient类可以作为给定Web services的客户端。
它有两种操作形式:
* WSDL 模式

* Non-WSDL 模式

在WSDL模式中,构造器可以使用WSDL文件名作为参数,并从WSDL中提取服务所使用的信息。

non-WSDL模式中使用参数来传递要使用的信息。

SoapServer类
这个类可以用来提供Web services。与SoapClient类似,SoapServer也有两种操作模式:WSDL模式和non-WSDL模式。这两种模式的意义跟 SoapClient的两种模式一样。在WSDL模式中,服务实现了WSDL提供的接口;在non-WSDL模式中,参数被用来管理服务的行为。
在SoapServer类的众多方法中,有三个方法比较重要。它们是SoapServer::setClass(),SoapServer::addFunction()和SoapServer::handle()。

下面给出实例
定义一个提供服务的php类,这个类所提供的函数就是web service对外提供的服务
(比较简单,例子略)

注意事项(非常重要)
php自带的soap扩展提供的类或构造函数是:SoapClient::SoapClient,详见《php5参考手册》 ;而nusoap提供的类库是:nusoap_client(有下划线) ,详见nusoap安装包源文件“lib/class.soapclient.php”文件。这里你会觉得很奇怪,为什么文件名不是带下划线"class.soap_client.php"?原来是这样的,nusoap为了兼容php自带的扩展soap的代码,在此类库文件最后面一行有如下代码:

if (!extension_loaded('soap')) {
class soapclient extends nusoap_client {
}
}
所以网上就出现了乱七八糟的 用第三方nusoap类库初始化soap客户端对象的例子,但是运行的时候程序都没有报错!例如:有的代码是 $client=new soapclient(); 有的是 $client = new nusoap_client(); 就是上面的原因!不过这里要说明的是,php扩展自带的soap类,已经能够很好的处理soap客户端调用,但是它的弊端就是如果它作为soap server要生成web service的WSDL,就显得无能为力了。而第三方的nusoap却恰好很容易生成WSDL。所以我这个项目就把两者都利用上了。【重要】为了不至于造成类库冲突,我还是修改了nusoap的 class.soapclient.php 文件的代码,把最后面的:
if (!extension_loaded('soap')) {
class soapclient extends nusoap_client {
}
}
删掉了。那么我打算这样,事实上也是尝试了很多方法都不行而被逼成这样的: php自带的soap扩展nusoap第三方类库必须在我的业务系统上共存兼容;我的业务系统(php代码实现)既是soap服务器端,也是soap客户端。我用nusoap作为我的soap server,因为客户的java机器要用web service调用我提供给它的函数,而且我要生成WDSL;而我的php脚本也要作为soap客户端调用客户java服务器上的函数的时候,不得不用php扩展自带soapclient这个类,至少我测试nusoap做soap client就是没法实现,soapclient这个自带的类库,也是侥幸可以调用。

==============================================================================

2) 同种语言的 web service 服务器端和客户端的实现
使用php soap扩展 建立 soap server和用php soap扩展的soapclient调用soap server 提供的函数非常简单,不用举例了。同理如果用java实现soap也应该很容易,不过我不懂。

3)使用php作为soap client去调用java xfire做的web service
调用wsdl的web service,从《php5参考手册》上看到的例子:
第一:调用成功

SoapClient::SoapClient
<?php
## 第一类方法初始化soapclient

$client = new SoapClient("some.wsdl"); ##方法一
$client = new SoapClient("some.wsdl", array('soap_version' => SOAP_1_2)); ##方法一
$client = new SoapClient("some.wsdl", array('login' => "some_name", ##方法一
'password' => "some_password"));
$client = new SoapClient("some.wsdl", array('proxy_host' => "localhost", ##方法一
'proxy_port' => 8080));
$client = new SoapClient("some.wsdl", array('proxy_host' => "localhost", ##方法一
'proxy_port' => 8080,
'proxy_login' => "some_name",
'proxy_password' => "some_password"));
## 下面是第二类方法初始化soapclient
$client = new SoapClient(null, array('location' => "http://localhost/soap.php",  ##方法二,注意 不可以带上"?wsdl"
'uri' => "http://test-uri/"));
$client = new SoapClient(null, array('location' => "http://localhost/soap.php",
'uri' => "http://test-uri/",
'style' => SOAP_DOCUMENT,
'use' => SOAP_LITERAL));
?>

据我测试 ,方法一(只要是明确指定了.wsdl文档的)完全行不通,如果使用方法一,那么总是无法与web service交互函数参数!总是报错,例如代码为:

$SoapClient = new SoapClient("http://192.168.100.187:8080/GBMP/services/CTIService?wsdl");
var_dump( $SoapClient->setICTCompanyInfo("中文字符")) ;
那么运行后,报错如下:
Fatal error: Uncaught SoapFault exception: [soap:Client] Not enough message parts were received for the operation
如果把上面的 wsdl文件下载下来后保存在本地,发现也不行!我猜测这可能与java有关,尽管soap是跨平台的。

【重要】后来发现只有方法二才能实现,代码如下:

$arrOptions=array(
//注意: 这个location指定的是server端代码在服务器中的具体位置, 而且不能在最后加上"?wdsl"字符串
'location'=>'http://192.168.100.187:8080/GBMP/services/CTIService',
#'location'=>'http://192.168.100.187:8080/GBMP/services/CTIService?wsdl', ##错误
'uri'=>'http://192.168.100.187:8080/',
);
$SoapClient = new SoapClient(null,$arrOptions); //实例化客户端对象
var_dump( $SoapClient->setICTCompanyInfo("中文字符"));
或者用:
$SoapClient->__call('setICTCompanyInfo',array("中文字符"));  ##如果用__call的方法调用,那么参数必须用一维索引数组!
第二:多参数的传递方法
如果要传递多个参数,可以直接在后面加参数列表就行,例如:
$SoapClient->setICTCompanyInfo("中文字符",$arg2,$arg3,......) ##这里有个陷阱,就是参数个数必须严格和server端函数一样,不可多传,否则报错
或者:
$SoapClient->__call('setICTCompanyInfo',array("中文字符",$arg2,$arg3,......))

提示:至于上面的soapclient功能 如何用 第三方类库(nusoap)实现,尝试过几次,发现都失败!暂时没有时间继续测试下去...

3) 使用php第三方类库nusoap输出wsdl文档
成功的源代码如下:

<?php
require('/lib/nusoap.php');
$nusoap_server = new nusoap_server();
$nusoap_server->soap_defencoding = 'UTF-8';  ##必须指定编码,否则如果参数有中文,那么对端会乱码
$nusoap_server->decode_utf8 = false;  ##必须指定编码,否则如果参数有中文,那么对端会乱码
$nusoap_server->configureWSDL('wsdl_test'); ##这里随便写吧,暂不知道有何用
$nusoap_server->register('getBccd',array('user'=>'xsd:string','pass'=>'xsd:string'),array('return'=>'xsd:string')); //正确

function getBccd($user,$pass){
return "Succeed! $user $pass 服务器 is ok!";
}
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA)?$HTTP_RAW_POST_DATA : '';
$nusoap_server->service($GLOBALS['HTTP_RAW_POST_DATA']);
?>

关于多参数的指定,在register()函数的第二个参数,必须是一个“关联数组”,上面“绿色”的对应关系,不多解释了!
其它:参考url:   http://blog.csdn.net/china_skag/article/details/7284227

$_POST:通过 HTTP POST 方法传递的变量组成的数组。是自动全局变量。
$GLOBALS['HTTP_RAW_POST_DATA'] :总是产生 $HTTP_RAW_POST_DATA 变量包含有原始的 POST 数据。此变量仅在碰到未识别 MIME 类型的数据时产生。$HTTP_RAW_POST_DATA 对于 enctype="multipart/form-data" 表单数据不可用。
也就是说基本上$GLOBALS['HTTP_RAW_POST_DATA'] 和 $_POST是一样的。
但是如果post过来的数据不是PHP能够识别的,你可以用 $GLOBALS['HTTP_RAW_POST_DATA']来接收,比如 text/xml 或者 soap 等等。
补充说明:PHP默认识别的数据类型是application/x-www.form-urlencoded标准的数据类型。
【好例子】

<?php
require_once("lib/nusoap.php");
$soap = new soap_server;
function savaNetData($moduleID,$pageArticleNumber,$webserverUrl){
$filename = 'config.txt';
$fp = fopen($filename, 'w+');

$content = "<config><moduleID>".$moduleID."</moduleID><number>".$pageArticleNumber
."</number><webserverUrl>".$webserverUrl."</webserverUrl></config>";
if ($fp) {
fwrite($fp, $content);
fclose($fp);
return 1;
} else {
die("Create File $filename error");
return -1;
}
}
$soap->configureWSDL("ServerPHPService",""); //初始化对WSDL的支持
// 注册服务
$soap->register('savaNetData',
array("moduleID"=>"xsd:int","pageArticleNumber"=>"xsd:int","webserverUrl"=>"xsd:string"), // 输入参数的定义
array("return"=>"xsd:int") // 返回值的定义
);
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA)?$HTTP_RAW_POST_DATA : '';
$soap->service($HTTP_RAW_POST_DATA);
?>

其它参考例子:
http://space.yoka.com/blog/923799/4665589.html

SOAP: java+xfire(web service) + php客户端的更多相关文章

  1. java axis web service

    编写 java调用web service的客户端比较简单,其中webservice为上一篇gsoap创建的server. package clientTest; import java.rmi.Rem ...

  2. <<Java RESTful Web Service实战>> 读书笔记

    <<Java RESTful Web Service实战>> 读书笔记 第一章   JAX-RS2.0入门 REST (Representational State ransf ...

  3. 【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)

    转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html 一,选择一个合适的,Web开发环境: 我选择的是Eclip ...

  4. XFire Web Service客户端开发

    一.项目创建: 创建一个Maven的web工程 Maven包导入pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0&qu ...

  5. (转)Java实现Web Service过程中处理SOAP Header的问题

    网上有篇文章,大致这么说的(如下文),最后我采用的wsimport  -XadditionalHeaders的方式. StrikeIron offers two authentication meth ...

  6. JAVA开发Web Service几种框架介绍

    郑重声明:此文为转载来的,出处已不知了,侵告删. 在讲Web Service开发服务时,需要介绍一个目前开发Web Service的几个框架,分别为Axis,axis2,Xfire,CXF以及JWS( ...

  7. (转)JAVA 调用Web Service的三种方法

    1.使用HttpClient用到的jar文件:commons-httpclient-3.1.jar方法:预先定义好Soap请求数据,可以借助于XMLSpy Professional软件来做这一步生成. ...

  8. XFire Web Service

    Web Service 创建HelloWorldService项目 首先要启动Web Service Project 向导.该向导由三个页面组成,第一页设置Web项目配置的详细信息:第二页设置XFir ...

  9. Java 调用Web service 加入认证头(soapenv:Header)

    前言 有时候调用web service 会出现 Message does not conform to configured policy [ AuthenticationTokenPolicy(S) ...

随机推荐

  1. Unicode基本概念

    Unicode是计算机可以支持这个星球上多种语言的秘密武器.通过使用一个或者多个字节来表示一个字符的方法突破了ASCII的限制.Unicode可以表示超过90000个字符. 使用方式:a=u'hell ...

  2. 转载:javascript 拖拽排序,简洁示例备忘

    转载自:http://blog.csdn.net/wang4978/article/details/6721157 <html> <head> <title>拖动行 ...

  3. 如何处理ABBYY中出现错误代码142和55的问题

    在使用ABBYY FineReader 12OCR文字识别软件创建PDF文件时,有时会出现以下错误提示:内部程序错误..\Src\SpecialFontFactory.cpp,142和内部程序错误.. ...

  4. js里的setTimeout和setInterval之后的页面是空白,阻塞浏览器的document对象,但是不阻塞script方法

    js里的setTimeout和setInterval是否进程阻塞? 阻塞浏览器的document对象,但是不阻塞script方法 当你在setTimeout中使用document.write时是不行的 ...

  5. IE10、IE11 无法写入Cookie

    IE10.IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题 你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的, ...

  6. window7 下 安装 apache24(httpd-2.4.10-x86-r2)加 php5.6(php-5.6.4-Win32-VC11-x86)加yaf(php_yaf-2.3.3-5.6-ts-vc11-x86)整合

    window7 下 安装 apache24(httpd-2.4.10-x86-r2)加 php5.6(php-5.6.4-Win32-VC11-x86)加yaf(php_yaf-2.3.3-5.6-t ...

  7. phonegap_android配置文档

    百度文库 http://wenku.baidu.com/link?url=C9l51orfpSrjMEK69-Yjh9hmmaqQj0DicfnYs5FSRhkdy8S62x1aBBwstFH-tJ9 ...

  8. 06 Linux下Shell介绍

    一.概述 每个人在成功登陆Linux后,系统会出现不同的提示符号,例如$,~,#等,然后你就可以开始输入需要的命令.若命令正确,系统就会依据命令的要求来执行,直到注销系统为止,在登陆到注销期间,输入的 ...

  9. php定时执行脚本

    php定时执行脚本 ignore_user_abort(); // run script. in background set_time_limit(0); // run script. foreve ...

  10. 分页写入文件,第二次分页前一定要关闭IO流啊。。否则文件写不全。。- -粗心