这篇文章主要介绍采用SOAP来建立以及访问Web service接口。

Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。

Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。

简而言之,当访问Web service,我们只需给定相应的数据条件就能够得到相应的信息。它的精华所在就是 能够跨平台跨语言 ,即PHP构建的客户端能够访问java构建的Web service、.NET构建的客户端能够访问PHP构建的Web service、A服务器能够访问使用B服务器中的函数等等!

2、相关知识

Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件(服务),使用WSDL文件进行(说明),并通过(UDDI)进行注册。

XML: (Extensible Markup Language)扩展型可标记语言。面向短期的临时数据处理、面向万维网络,是Soap的基础。

Soap: (Simple Object Access Protocol)简单对象存取协议。是XML Web Service 的通信协议。当用户通过UDDI找到你的WSDL描述文档后,他通过可以SOAP调用你建立的Web服务中的一个或多个操作。SOAP是XML文档形式的调用方法的规范,它可以支持不同的底层接口,像HTTP(S)或者SMTP。

WSDL: (Web Services Description Language) WSDL 文件是一个 XML 文档,用于说明一组 SOAP 消息以及如何交换这些消息。大多数情况下由软件自动生成和使用。

WSDL(Web Service Description Language)Web服务器描述语言是用XML文档来描述Web服务的标准,是Web服务的接口定义语言,由Ariba、Intel、IBM、MS等共同提出,通过WSDL,可描述Web服务的三个基本属性:

  • 服务做些什么——服务所提供的操作(方法)
  • 如何访问服务——和服务交互的数据格式以及必要协议
  • 服务位于何处——协议相关的地址,如URL
  • WSDL文档以端口集合的形式来描述Web服务,WSDL 服务描述包含对一组操作和消息的一个抽象定义,绑定到这些操作和消息的一个具体协议,和这个绑定的一个网络端点规范。WSDL 文档被分为两种类型: 服务接口(service interface ) 服务实现(service implementations)

    服务接口文档中的主要元素为types、message、operation、portType、binding、port和service,他们的作用分别为:

    types: 定义了Web服务使用的所有数据类型集合,可被元素的各消息部件所引用。它使用某种类型系统(一般地使用XML Schema中的类型系统)。

    message: 通信消息数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。

    operation: 对服务中所支持操作的抽象描述。一般单个operation描述了一个访问入口的请求/响应消息对。

    portType: 对于某个访问入口点类型所支持操作的抽象集合。这些操作可以由一个或多个服务访问点来支持。

    binding: 包含了如何将抽象接口的元素(portType)转变为具体表示的细节,具体表示也就是指特定的数据格式和协议的结合;特定端口类型的具体协议和数据格式规范的绑定。

    port: 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。

    service: 这是一个粗糙命名的元素,代表端口的集合;相关服务访问点的集合。

    总结来看 ,portType(与message和type元素的细节相结合)描述了Web服务是什么,binding元素描述了如何使用Web服务,port及service元素描述了Web服务的位置。

    3、访问大概流程

    1、客户根据WSDL描述文档,会生成一个SOAP请求消息。(客户生成的SOAP请求会被嵌入在一个HTTP POST请求中,发送到Web服务器中。)

    2、Web服务器再把这些请求转发给Web service请求处理器。(请求处理器的作用在于,解析收到的SOAP请求,调用Webservice,然后再生成相应的SOAP应答)

    3、Web服务器得到SOAP应答后,会再通过HTTP应答的方式把它送回到客户端。

    忽略其中的细节,简而言之就是浏览器访问Web服务器A中的相应程序(即服务器A定义调用服务器B Web service的应用程序,此程序是客户端);Web服务器B响应该请求,并调用执行相应的程序,最终以http响应将数据发给Web服务器A;Web服务器A在返回给浏览器。

    SOAP使用HTTP传送XML,尽管HTTP不是有效率的通讯协议,而且XML还需要额外的文件解析(parse),两者使得交易的速度大大低于其它方案。
    但是XML是一个开放、健全、有语义的讯息机制,而HTTP是一个广泛又能避免许多关于防火墙的问题,从而使SOAP得到了广泛的应用。
    但是如果效率对自己来说很重要,那么应该多考虑其它的方式,而不要用SOAP。

    可以参考下面的简图(具体细节忽略):

    4、小试牛刀(访问国内飞机航班时刻表 WEB 服务)

    接下来我们将来访问国内飞机航班时刻表 WEB 服务,先了解一些基本服务的情况。

    该网站提供一些Web服务: http://www.webxml.com.cn/zh_cn/web_services.aspx

    我们将选取国内飞机航班时刻表 WEB 服务来进行访问!

    从上图中我们可以看到一个Web服务含有三个链接,分别代表三种途径Endpoint、Disco、WSDL。

    那它们有什么不同呢?

    Endpoint:web服务的URI地址,你访问之后,就会出现web服务的相关类描述、方法列表以及方法描述。

    Disco:通过这个可以找到该web服务。即利用了web服务发现机制中的一种发现机制disco。

    WSDL: 该web服务的描述性语言。即Web Services Description Language。用来描述你的web服务定义的方法和属性、binding协议部分、port端口以及服务URI。
    我们当然是使用WSDL啦!

    参考上面WSDL的介绍我们很容易就能看明白这个文件。

    在PHP中存在一个扩展SOAP,使用它是很方便处理相应的SOAP类Web service!

    1、首先我们点击进入该WSDL文件,查看这个Web service提供什么功能、有什么方法、以及使用方法的参数、返回的结果类型等等。

    我们将使用getDomesticAirlinesTime()进行测试

    该方法需要填入相应的参数,包括出发城市、抵达城市、出发日期、(商业用户ID)

    2、接下来使用PHP中的SOAP扩展中的SoapClient类进行访问该Web service

    该文件我命名为test99.php

     1 <?php
     2 header("Content-type:text/html;charset=utf-8;");
     3 $client = new SoapClient("http://ws.webxml.com.cn/webservices/DomesticAirline.asmx?wsdl");
     4 echo "<pre>";
     5 print_r($client->__getFunctions());     #查看该WSDL所有方法
     6 echo "</pre>";
     7 $arr=array('startCity'=>'北京', 'lastCity'=>'广州', 'theDate'=>'2017-05-22');    #参数信息、数组形势
     8 $a=$client->getDomesticAirlinesTime($arr);
     9 echo "<pre>";
    10 print_r($a);
    11 echo "</pre>";
    12 $c= $client->__soapCall('getDomesticAirlinesTime', array('getDomesticAirlinesTime'=>$arr));
    13 echo "<pre>";
    14 print_r($c);
    15 echo "</pre>";die;
    

      浏览器访问test99.php,结果如下

    5、用牛刀宰牛啦(使用SOAP构建Web service)

      PHP中的SOAP可分为WSDL类型SOAP与非WSDL类型SOAP,现如今大多数使用的SOAP是含有WSDL的。个人对与这两种的理解是:含WSDL是标准类型的,因为WSDL使用了XML标准语法对你提供的方法类进行了描述(描述服务)。接下来我们将构建WSDL类型的SOAP Web service接口。

      目录构造如下:

      1、先构造好我们需要提供服务的功能方法

      Webserciec.class.php(这个类很简单,只是做个测试;当然这里可以写我们想要提供的任何功能,各种逻辑,以及数据服务等等。)

     1 <?php
     2 Class WebService
     4     public function getTest($a)
     6         return "The msg from WebService".$a;
     8     public function test($b,$c)
    10         return $b+$c;
    11     }
    12 }
    

      2、构建WSDL文件(即使用WSDL对Webservice.class.php类文件进行相应的服务描述)

      由于PHP中没有将该类生成WSDL文件的功能函数,因此我们需要借助别的工具将WSDL文件构造出来!

      下面是一个SoapDiscovery.class.php类文件,可以生成相应的WSDL文件

      1 <?php
      3 /**
      5 * All rights reserved.
      7 * Redistribution and use in source and binary forms, with or without modification, are
      8 * permitted provided that the following conditions are met:
     10 *     Redistributions of source code must retain the above copyright notice, this list of
     11 *     conditions and the following disclaimer. 
     12 *     Redistributions in binary form must reproduce the above copyright notice, this list of
     13 *     conditions and the following disclaimer in the documentation and/or other materials
     14 *     provided with the distribution. 
     15 *     Neither the name of the Solsoft de Costa Rica S.A. nor the names of its contributors may
     16 *     be used to endorse or promote products derived from this software without specific
     17 *     prior written permission.
     18 * 
     19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
     20 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
     21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32 * 
     33 *
     34 * @version $Id: SoapDiscovery.class.php 66 2013-04-10 07:12:21Z ideaa $
     35 * @copyright 2005 
     36 */
     38 /**
     39 * SoapDiscovery Class that provides Web Service Definition Language (WSDL).
     40 * 
     41 * @package SoapDiscovery
     42 * @author Braulio Jos?Solano Rojas
     44 * @version $Id: SoapDiscovery.class.php 66 2013-04-10 07:12:21Z ideaa $
     45 * @access public
     46 * */
     47 class SoapDiscovery {
     49     private $class_name = '';
     50     private $service_name = '';
     51     private $address = '';
     53     /**
     54      * SoapDiscovery::__construct() SoapDiscovery class Constructor.
     55      * 
     56      * @param string $class_name
     57      * @param string $service_name
     58      * */
     59     public function __construct($class_name = '', $service_name = '', $address = '') {
     60         $this->class_name = $class_name;
     61         $this->service_name = $service_name;
     62         $this -> address = $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['PHP_SELF'];
     63         if(!empty($address))
     64         $this -> address = $address;
     65     }
     67     /**
     68      * SoapDiscovery::getWSDL() Returns the WSDL of a class if the class is instantiable.
     69      * 
     70      * @return string
     71      * */
     72     public function getWSDL() {
     73         if (empty($this->service_name)) {
     74             throw new Exception('No service name.');
     75         }
     76         $headerWSDL = "<?xml version=\"1.0\" ?>\n";
     77         $headerWSDL.= "<definitions name=\"$this->service_name\" targetNamespace=\"urn:$this->service_name\" xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:tns=\"urn:$this->service_name\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns=\"http://schemas.xmlsoap.org/wsdl/\">\n";
     78         $headerWSDL.= "<types xmlns=\"http://schemas.xmlsoap.org/wsdl/\" />\n";
     80         if (empty($this->class_name)) {
     81             throw new Exception('No class name.');
     82         }
     84         $class = new ReflectionClass($this->class_name);
     86         if (!$class->isInstantiable()) {
     87             throw new Exception('Class is not instantiable.');
     88         }
     90         $methods = $class->getMethods();
     92         $portTypeWSDL = '<portType name="' . $this->service_name . 'Port">';
     93         $bindingWSDL = '<binding name="' . $this->service_name . 'Binding" type="tns:' . $this->service_name . "Port\">\n<soap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\" />\n";
     94         $serviceWSDL = '<service name="' . $this->service_name . "\">\n<documentation />\n<port name=\"" . $this->service_name . 'Port" binding="tns:' . $this->service_name . "Binding\"><soap:address location=\"".$this ->address."\" />\n</port>\n</service>\n";
     95         $messageWSDL = '';
     96         foreach ($methods as $method) {
     97             if ($method->isPublic() && !$method->isConstructor()) {
     98                 $portTypeWSDL.= '<operation name="' . $method->getName() . "\">\n" . '<input message="tns:' . $method->getName() . "Request\" />\n<output message=\"tns:" . $method->getName() . "Response\" />\n</operation>\n";
     99                 $bindingWSDL.= '<operation name="' . $method->getName() . "\">\n" . '<soap:operation soapAction="urn:' . $this->service_name . '#' . $this->class_name . '#' . $method->getName() . "\" />\n<input><soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</input>\n<output>\n<soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</output>\n</operation>\n";
    100                 $messageWSDL.= '<message name="' . $method->getName() . "Request\">\n";
    101                 $parameters = $method->getParameters();
    102                 foreach ($parameters as $parameter) {
    103                     $messageWSDL.= '<part name="' . $parameter->getName() . "\" type=\"xsd:string\" />\n";
    104                 }
    105                 $messageWSDL.= "</message>\n";
    106                 $messageWSDL.= '<message name="' . $method->getName() . "Response\">\n";
    107                 $messageWSDL.= '<part name="' . $method->getName() . "\" type=\"xsd:string\" />\n";
    108                 $messageWSDL.= "</message>\n";
    109             }
    110         }
    111         $portTypeWSDL.= "</portType>\n";
    112         $bindingWSDL.= "</binding>\n";
    113         //return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>');
    114         //生成wsdl文件,将上面的return注释
    115         $fso = fopen($this->class_name . ".wsdl", "w");
    116         fwrite($fso, sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'));
    117     }
    119     /**
    120      * SoapDiscovery::getDiscovery() Returns discovery of WSDL.
    121      * 
    122      * @return string
    123      * */
    124     public function getDiscovery() {
    125         return "<?xml version=\"1.0\" ?>\n<disco:discovery xmlns:disco=\"http://schemas.xmlsoap.org/disco/\" xmlns:scl=\"http://schemas.xmlsoap.org/disco/scl/\">\n<scl:contractRef ref=\"http://" . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['PHP_SELF'] . "?wsdl\" />\n</disco:discovery>";
    126     }
    128 }
    130 ?>
    View Code

      getWSDL.php文件

    1 <?php
    2 include ('./WebService.class.php');
    3 include ('./SoapDiscovery.class.php');
    4 $wsdl =new SoapDiscovery('WebService','a','http://www.test99.com/ok/server.php');  #第一个是参数为类名、第二个参数为服务名(可以随便写)、第三个参数为提供服务的接口文件
    5 $wsdl -> getWSDL();
    

      访问http://www.test99.com/ok/getWSDL.php,即可生成WebService.WSDL文件

     1 <?xml version="1.0" ?>
     2 <definitions name="a" targetNamespace="urn:a" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="urn:a" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/">
     3 <types xmlns="http://schemas.xmlsoap.org/wsdl/" />
     4 <portType name="aPort"><operation name="getTest">
     5 <input message="tns:getTestRequest" />
     6 <output message="tns:getTestResponse" />
     7 </operation>
     8 <operation name="test">
     9 <input message="tns:testRequest" />
    10 <output message="tns:testResponse" />
    11 </operation>
    12 </portType>
    13 <binding name="aBinding" type="tns:aPort">
    14 <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
    15 <operation name="getTest">
    16 <soap:operation soapAction="urn:a#WebService#getTest" />
    17 <input><soap:body use="encoded" namespace="urn:a" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
    18 </input>
    19 <output>
    20 <soap:body use="encoded" namespace="urn:a" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
    21 </output>
    22 </operation>
    23 <operation name="test">
    24 <soap:operation soapAction="urn:a#WebService#test" />
    25 <input><soap:body use="encoded" namespace="urn:a" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
    26 </input>
    27 <output>
    28 <soap:body use="encoded" namespace="urn:a" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
    29 </output>
    30 </operation>
    31 </binding>
    32 <service name="a">
    33 <documentation />
    34 <port name="aPort" binding="tns:aBinding"><soap:address location="http://www.test99.com/ok/server.php" />
    35 </port>
    36 </service>
    37 <message name="getTestRequest">
    38 <part name="a" type="xsd:string" />
    39 </message>
    40 <message name="getTestResponse">
    41 <part name="getTest" type="xsd:string" />
    42 </message>
    43 <message name="testRequest">
    44 <part name="b" type="xsd:string" />
    45 <part name="c" type="xsd:string" />
    46 </message>
    47 <message name="testResponse">
    48 <part name="test" type="xsd:string" />
    49 </message>
    50 </definitions>
    View Code

      3、建立Server.php服务文件

    1 <?php
    2 include("WebService.class.php");
    3 $server = new SoapServer("WebService.wsdl");
    4 $server -> setClass("WebService");
    5 $server -> handle();
    

      大功告成,给外部提供接口,http://www.test99.com/ok/Server.php?wsdl

      4、开始访问,在www.test88.com主机中建立客户端程序

      Client.php

     1 header("Content-type:text/html;charset=utf-8;");
     2 $client = new SoapClient("http://www.test99.com/ok/Server.php?wsdl");
     3 echo "<pre>";
     4 print_r($client->__getFunctions());
     5 echo "</pre>";
     6 echo $client->__soapCall('test',array('1','2'));
     7 echo "<br/>";
     8 try{  
     9     echo  $result=$client -> test('2','2');
    10 }catch(SoapFault $e){
    11     echo $e->getMessage();
    

      访问http://www.test88.com/Client.php,结果如下所示:

      根据上图我们采用SOAP建立Web service成功!建立Web service就是这么简单

      当然我这里仅仅只是建立了一个对外开放的Web服务,但是这个服务如果不加以说明注释别人肯定不知道这个服务有什么作用呀、该怎么使用呀等等。这些东西在这篇文章中还没有提到,大家需切记哈!

    (以上是自己的一些见解,若有不足或者错误的地方请各位指出)

     作者:那一叶随风   http://www.cnblogs.com/phpstudy2015-6/

     原文地址:http://www.cnblogs.com/phpstudy2015-6/p/6842463.html 

     声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接