Web Service

Web service 是一个软件系统,设计来支持计算机之间跨网络相互访问。在Web应用程序,它通常用一套API,可以被互联网访问和执行在远端系统主机上的被请求服务。系统主机所要求的服务。例如,以Flex为基础的客户端可能会援引函数实现在服务器端运行PHP的Web应用程序。 Web service依赖SOAP作为通信协议栈的基础层。

Yii提供CWebServiceCWebServiceAction简化了在Web应用程序实现Web service。这些API以类形式实现,被称为service providers. Yii将为每个类产生一个WSDL,描述什么API有效和客户端怎么援引。当客户端援引API,Yii将实例化相应的service provider和调用被请求的API来完成请求。

注: CWebService 依靠PHP SOAP extension 。请确定您是否在试用本节中的例子前允许此扩展。

1. Defining Service Provider(定义Service Provider)

正如我们上文所述,service provider是一个类定义能被远程援引的方法。Yii依靠doccomment and classreflection识别哪些方法可以被远程调用和他们的参数还有返回值。

让我们以一个简单的股票报价服务开始。这项服务允许客户端请求指定股票的报价。我们确定service provider如下。请注意,我们定义扩展CController的提供类StockController。这是不是必需的。马上我们将解释为什么这样做。

  1. class StockController extends CController
  2. {
  3. /**
  4. * @param string the symbol of the stock
  5. * @return float the stock price
  6. * @soap
  7. */
  8. public function getPrice($symbol)
  9. {
  10. $prices=array('IBM'=>100, 'GOOGLE'=>350);
  11. return isset($prices[$symbol])?$prices[$symbol]:0;
  12. //...return stock price for $symbol
  13. }
  14. }

在上面的,我们通过在文档注释中的@soap标签声明getPrice方法为一个Web service API。依靠文档注释指定输入的参数数据类型和返回值。其他的API可使用类似方式声明。

2. Declaring Web Service Action(定义Web Service动作)

已经定义了service provider,我们使他能够通过客户端访问。特别是,我们要创建一个控制器动作暴露这个服务。可以做到这一点很容易,在控制器类中定义一个CWebServiceAction动作。对于我们的例子中,我们把它放在StockController中。

  1. class StockController extends CController
  2. {
  3. public function actions()
  4. {
  5. return array(
  6. 'quote'=>array(
  7. 'class'=>'CWebServiceAction',
  8. ),
  9. );
  10. }
  11.  
  12. /**
  13. * @param string the symbol of the stock
  14. * @return float the stock price
  15. * @soap
  16. */
  17. public function getPrice($symbol)
  18. {
  19. //...return stock price for $symbol
  20. }
  21. }

这就是我们需要建立的Web service!如果我们尝试访问动作网址http://hostname/path/to/index.php?r=stock/quote ,我们将看到很多XML内容,这实际上是我们定义的Web service的WSDL描述。

提示:在默认情况下, CWebServiceAction 假设当前的控制器 是service provider。这就是因为我们定义 getPrice方法在StockController中。

3. Consuming Web Service(消费Web Service)

要完成这个例子,让我们创建一个客户端来消费我们刚刚创建的Web service。例子中的客户端用php编写的,但可以用别的语言编写,例如Java, C#, Flex等等。

  1. $client=new SoapClient('http://hostname/path/to/index.php?r=stock/quote');
  2. echo $client->getPrice('GOOGLE');

在网页中或控制台模式运行以上脚本,我们将看到GOOGLE的价格350

4. Data Types(数据类型)

当定义的方法和属性被远程访问,我们需要指定输入和输出参数的数据类型。以下的原始数据类型可以使用:

  • str/string: 对应 xsd:string;
  • int/integer: 对应 xsd:int;
  • float/double: 对应 xsd:float;
  • bool/boolean: 对应 xsd:boolean;
  • date: 对应 xsd:date;
  • time: 对应 xsd:time;
  • datetime: 对应 xsd:dateTime;
  • array: 对应 xsd:string;
  • object: 对应 xsd:struct;
  • mixed: 对应 xsd:anyType.
    如果类型不属于上述任何原始类型,它被看作是复合型组成的属性。复合型类型被看做类,他的属性当做类的公有成员变量,在文档注释中被用@soap标记。

我们还可以使用数组类型通过附加[]在原始或复合型类型的后面。这将定义指定类型的数组。

下面就是一个例子定义getPosts网页API,返回一个Post对象的数组。

  1. class PostController extends CController
  2. {
  3. /**
  4. * @return Post[] a list of posts
  5. * @soap
  6. */
  7. public function getPosts()
  8. {
  9. return Post::model()->findAll();
  10. }
  11. }
  12.  
  13. class Post extends CActiveRecord
  14. {
  15. /**
  16. * @var integer post ID
  17. * @soap
  18. */
  19. public $id;
  20. /**
  21. * @var string post title
  22. * @soap
  23. */
  24. public $title;
  25. }

5. Class Mapping(类映射)

为了从客户端得到复合型参数,应用程序需要定义从WSDL类型到相应PHP类的映射。这是通过配置CWebServiceAction的属性classMap

  1. class PostController extends CController
  2. {
  3. public function actions()
  4. {
  5. return array(
  6. 'service'=>array(
  7. 'class'=>'CWebServiceAction',
  8. 'classMap'=>array(
  9. 'Post'=>'Post', // or simply 'Post'
  10. ),
  11. ),
  12. );
  13. }
  14. ......
  15. }

6. Intercepting Remote Method Invocation(拦截远程方法调用)

通过实现IWebServiceProvider接口,sevice provider可以拦截远程方法调用。在IWebServiceProvider::beforeWebMethod ,sevice provider可以获得当前CWebService实例和通过CWebService::methodName请求的方法的名字 。它可以返回假如果远程方法出于某种原因不应被援引(例如:未经授权的访问) 。

原文: https://www.yiiframework.com/doc/guide/1.1/zh-cn/topics.webservice