微服务常见架构方案及基础框架

微服务(MicroServices)架构是当前互联网业界的一个技术热点,圈里有不少同行朋友当前有计划在各自公司开展微服务化体系建设,他们都有相同的疑问:

一个微服务架构有哪些技术关注点(technical concerns)?

需要哪些基础框架或组件来支持微服务架构?

这些框架或组件该如何选型? Continue reading “微服务常见架构方案及基础框架”

分布式系统的Raft算法

过去,Paxos一直是分布式协议的标准,但是Paxos难于理解,更难以实现,Google的分布式锁系统Chubby作为Paxos实现曾经遭遇到很多坑。

来自Stanford的新的分布式协议研究称为Raft,它是一个为真实世界应用建立的协议,主要注重协议的落地性和可理解性。

在了解Raft之前,我们先了解Consensus一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服务器可能会崩溃或变得不可靠,它就不能和其他服务器达成一致状态。这样就需要一种Consensus协议,一致性协议是为了确保容错性,也就是即使系统中有一两个服务器当机,也不会影响其处理过程。

为了以容错方式达成一致,我们不可能要求所有服务器100%都达成一致状态,只要超过半数的大多数服务器达成一致就可以了,假设有N台服务器,N/2 1 就超过半数,代表大多数了。

Paxos和Raft都是为了实现Consensus一致性这个目标,这个过程如同选举一样,参选者需要说服大多数选民(服务器)投票给他,一旦选定后就跟随其操作。Paxos和Raft的区别在于选举的具体过程不同。

Continue reading “分布式系统的Raft算法”

CAP原理和BASE思想

分布式领域CAP理论
Consistency(一致性), 数据一致更新,所有数据变动都是同步的
Availability(可用性), 好的响应性能
Partition tolerance(分区容错性) 可靠性

定理:任何分布式系统只可同时满足二点,没法三者兼顾。
忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

Continue reading “CAP原理和BASE思想”

JSON-RPC、XML-RPC、SOAP三者的关系

JSON-RPC规范:http://json-rpc.org/wiki/specification

XML-RPC规范:http://www.xmlrpc.com/spec

SOAP规范:http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383487

参考:http://weblog.masukomi.org/writings/xml-rpc_vs_soap.htm

三者都是为了实现RPC中的消息交换,并且都没有定义传输协议。不过为了更方便在网络中传输,而且由于HTTP的无状态性,都使得HTTP为这三者的常用的传输协议。下面例子也是基于HTTP协议的

XML-RPC和SOAP都是基于XML格式的消息交换:

XML-RPC非常简单,定义了几种基本类型、匿名结构体、匿名数组;

SOAP除了基本类型、命名结构体、命名数组以外,还可以自定义类型,能使用多态的方法调用方式

而JSON-RPC是基于JSON格式的消息交换,JSON比XML更加轻巧,并且非常容易在页面JS中使用,其他特点与XML-RPC类似

下面是使用这几种协议发送请求的例子:

XML-RPC

Xhtml代码
  1. POST /RPC2 HTTP/1.0  
  2. User-Agent: Frontier/5.1.2 (WinNT)  
  3. Host: betty.userland.com  
  4. Content-Type: text/xml  
  5. Content-length: 181  
  6.   
  7.   
  8.   
  9. <?xml version=”1.0″?>  
  10. <methodCall>  
  11.    <methodName>examples.getStateName</methodName>  
  12.    <params>  
  13.       <param>  
  14.          <value><i4>41</i4></value>  
  15.          </param>  
  16.       </params>  
  17.    </methodCall>  

SOAP:

Xhtml代码
  1. POST /StockQuote HTTP/1.1  
  2. Host: www.stockquoteserver.com  
  3. Content-Type: text/xml; charset=”utf-8″  
  4. Content-Length: nnnn  
  5. SOAPAction: “Some-URI”  
  6.   
  7. <SOAP-ENV:Envelope  
  8.   xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”  
  9.   SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”/>  
  10.    <SOAP-ENV:Header>  
  11.        <t:Transaction  
  12.            xmlns:t=”some-URI”  
  13.            SOAP-ENV:mustUnderstand=”1″>  
  14.                5  
  15.        </t:Transaction>  
  16.    </SOAP-ENV:Header>  
  17.    <SOAP-ENV:Body>  
  18.        <m:GetLastTradePrice xmlns:m=”Some-URI”>  
  19.            <symbol>DEF</symbol>  
  20.        </m:GetLastTradePrice>  
  21.    </SOAP-ENV:Body>  
  22. </SOAP-ENV:Envelope>  

JSON:

Javascript代码
  1. –> { “method”: “echo”, “params”: [“Hello JSON-RPC”], “id”: 1}  
  2. <– { “result”: “Hello JSON-RPC”, “error”: null, “id”: 1} 

PHP SOAP实例讲解

一、什么是soap,什么是wsdl,为什么要用他们

SOAP是基于XML和HTTP通信协议,xml各种平台,各种语言都支持的一个种语言。http呢它得到了所有的因特网浏览器及服务器的支持。

WSDL 指网络服务描述语言 (Web Services Description Language),是一种使用 XML 编写的文档。这种文档可描述某个 Web service。它可规定服务的位置,以及此服务提供的操作。

我是做php的,你是java的,他是做.net,如果我们三个之间要进行通信,要进行数据交换,怎么办呢?我们需要一个能和我们都能通信的工具。soap,wsdl被创造出来,使得运行在不同的操作系统并使用不同的技术和编程语言的应用程序可以互相进行通信。

二、实例

如果php要使用soap的话,通常做法是,添加了一下php的soap模块,在php.ini里面加上soap.so,下面介绍一个不要添加soap.so文件,也可以实现soa

  1. <?php    
  2. //包函nusoap.php  
  3. require_once(‘./lib/nusoap.php’);  
  4.   
  5. //创建服务端  
  6. $server = new soap_server;  
  7.   
  8. //定义客户端调用方法  
  9. $server->register(‘hello’);  
  10.   
  11. //调用方法以及参数  
  12. function hello($name) {  
  13.     return ‘Hello, ‘ . $name;  
  14. }  
  15.   
  16. $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : ;  
  17. $server->service($HTTP_RAW_POST_DATA);  
  18. ?>    

p的方法

nusoap是php写的一个功能文件,包涵进来就可以用了,网上很多自己去搜一下吧。

1、不使用wsdl

a、服务端helloworld2.php

b、客户端hello.php

  1. <?php    
  2. //包函nusoap.php  
  3. require_once(‘./lib/nusoap.php’);  
  4. //新建一个soap客户端,调用服务端提供的wsdl  
  5. //$client = new soapclient(‘http://localhost/test/hellowsdl2.php?wsdl’, true);  
  6. $client = new soapclient(‘http://localhost/test/helloworld2.php’);  
  7. //查看一下是不是报错  
  8. $err = $client->getError();  
  9. if ($err) {  
  10.     //显示错误  
  11.     echo ‘<h2>Constructor error</h2><pre>’ . $err . ‘</pre>’;  
  12. }  
  13.   
  14. //调用服务端的方法  
  15. $result = $client->call(‘hello’array(‘person’ => “this is a test”));  
  16.   
  17. echo ‘<h2>Result</h2><pre>’;  
  18. print_r($result);  
  19. echo ‘</pre>’;  
  20. ?>    

2、使用wsld

a、服务器端

  1. <?php    
  2. //包函nusoap.php  
  3. require_once(‘./lib/nusoap.php’);  
  4. //新建一个soap服务  
  5. $server = new soap_server();  
  6. //初始化支持wsdl  
  7. $server->configureWSDL(‘hellowsdl2’‘urn:hellowsdl2’);  
  8. //定义数据结构来接收数据  
  9. $server->wsdl->addComplexType(  
  10.     ‘Person’,  
  11.     ‘complexType’,  
  12.     ‘struct’,  
  13.     ‘all’,  
  14.     ,  
  15.     array(  
  16.         ‘firstname’ => array(‘name’ => ‘firstname’‘type’ => ‘xsd:string’),//后面的type定义数据的类型,这个是string  
  17.         ‘age’ => array(‘name’ => ‘age’‘type’ => ‘xsd:int’),//后面的type定义数据的类型,这个是int  
  18.         ‘gender’ => array(‘name’ => ‘gender’‘type’ => ‘xsd:string’)//后面的type定义数据的类型,这个是string  
  19.     )  
  20. );  
  21. $server->wsdl->addComplexType(  
  22.     ‘SweepstakesGreeting’,  
  23.     ‘complexType’,  
  24.     ‘struct’,  
  25.     ‘all’,  
  26.     ,  
  27.     array(  
  28.         ‘greeting’ => array(‘name’ => ‘greeting’‘type’ => ‘xsd:string’),  
  29.         ‘winner’ => array(‘name’ => ‘winner’‘type’ => ‘xsd:string’)  
  30.     )  
  31. );  
  32. //服务器定义的soap调用方法  
  33. $server->register(‘hello’,                    // 方法名字hello,方法就在下面  
  34.     array(‘person’ => ‘tns:Person’),          // 客户端传来的变量  
  35.     array(‘return’ => ‘tns:SweepstakesGreeting’),    //返回参数  
  36.     ‘urn:hellowsdl2’,                         // soap名  
  37.     ‘urn:hellowsdl2#hello’,                   // soap的方法名  
  38.     ‘rpc’,                                    // 使用的方式  
  39.     ‘encoded’,                                // 编码  
  40.     ‘test’                                    // 存档  
  41. );  
  42. //定义上面注册过的函数hello  
  43. function hello($person) {  
  44.     $greeting = ‘Hello, ‘.$person[‘firstname’].‘. It is nice to meet a ‘.$person[‘age’].‘ year old ‘.$person[‘gender’].‘.’;  
  45.   
  46.     $winner =  ‘Scott’;  
  47.     //要返回的数据  
  48.     return array(  
  49.         ‘greeting’ => $greeting,  
  50.         ‘winner’ => $winner  
  51.     );  
  52. }  
  53. // 请求时(试图)调用服务  
  54. $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : ;  
  55. $server->service($HTTP_RAW_POST_DATA);  
  56. ?>    

b、客户端

  1. <?php  
  2. //包函nusoap.php  
  3. require_once(‘./lib/nusoap.php’);  
  4. //新建一个soap客户端,调用服务端提供的wsdl  
  5. //$client = new soapclient(‘http://localhost/test/hellowsdl2.php?wsdl’, true);  
  6. $client = new soapclient(‘http://localhost/test/helloworld2.php’);  
  7. //查看一下是不是报错  
  8. $err = $client->getError();  
  9. if ($err) {  
  10.  //显示错误  
  11.  echo ‘<h2>Constructor error</h2><pre>’ . $err . ‘</pre>’;  
  12. }  
  13. //要向服务端要传的参数  
  14. $person = array(‘firstname’ => ‘Willi’, ‘age’ => 22, ‘gender’ => ‘male’);  
  15.   
  16. //调用服务端的方法  
  17. $result = $client->call(‘hello’, array(‘person’ => $person));  
  18. //错误审核  
  19. if ($client->fault) {  
  20.  echo ‘<h2>Fault</h2><pre>’;  
  21.  print_r($result);  
  22.  echo ‘</pre>’;  
  23. else {  
  24.  $err = $client->getError();  
  25.  if ($err) {  
  26.  echo ‘<h2>Error</h2><pre>’ . $err . ‘</pre>’;  
  27.  } else {  
  28.  echo ‘<h2>Result</h2><pre>’;  
  29.  print_r($result);  
  30.  echo ‘</pre>’;  
  31.  }  
  32. }  
  33. //显示请求信息  
  34. echo ‘<h2>Request</h2>’;  
  35. echo ‘<pre>’ . htmlspecialchars($client->request, ENT_QUOTES) . ‘</pre>’;  
  36. //显示返回信息  
  37. echo ‘<h2>Response</h2>’;  
  38. echo ‘<pre>’ . htmlspecialchars($client->response, ENT_QUOTES) . ‘</pre>’;  
  39. //显示调试信息  
  40. echo ‘<h2>Debug</h2>’;  
  41. echo ‘<pre>’ . htmlspecialchars($client->debug_str, ENT_QUOTES) . ‘</pre>’;  
  42. ?>  

上面二个例子不管是客户端,还是服务器端,都是用php写的,你可以试着用多种语言来写,来测试一下。不管你是用php的模块,还是用nusoap,里面具体方法就不在这多说了,手册里面都有。

 

 

 

 SOAP在这里就不用介绍了,  这里只是简单的实现一个SOAP的实例, 不多说 ,看代码吧。 soap分为server和client, 我们要使client去调用server的代码. 首先看server短的代码:

 

这个是server端的代码: server.php

<?php

    //声明一个函数add() ,并返回它的值
        function add($a,$b){
        return $a+$b;
        }

    //实例化一个SoapServer对象, 并将add函数注册成为其方法
        $server = new SoapServer(null,array(‘uri’=>’http://localhost/’)); //指定server端代码的URI(资源标志符)
        $server->addFunction(“add”);
        $server->handle();
?>

然后使用client端的代码来调用server端的代码: client的代码也很简单: 如下:

这个是client端的代码 client.php

<?php

    //建立一个参数数组,存储要访问的提供soap服务的计算机的地址与程序
        $arrOptions=array(
            ‘uri’=>’http://localhost/’,
            ‘location’=>’http://localhost/soap/server.php’,  //注意: 这个location指定的是server端代码在服务器中的具体位置, 我的是在本地根目录下的soap目录中,
            ‘trace’=>true,
        );
        $soapObject = new SoapClient(null,$arrOptions); //实例化客户端对象
        echo $soapObject->add(20,30); //调用服务器端的函数add并返回值50
?>

ok, 结束了 !

PHP中使用XML-RPC构造Web Service简单入门

[  Web Service介绍 ]

Web Service就是为了异构系统的通信而产生的,它基本的思想就是使用基于XML的HTTP的远程调用提供一种标准的机制,而省去建立一种新协议的需求。 目前进行Web Service通信有两种协议标准,一种是XML-RPC,另外一种是SOAP。XML-RPC比较简单,出现时间比较早,SOAP比较复杂,主要是一些 需要稳定、健壮、安全并且复杂交互的时候使用。

PHP中集成了XML-RPC和SOAP两种协议的访问,都是集中在xmlrpc扩展当 中。另外,在PHP的PEAR中,不管是PHP 4还是PHP 5,都已经默认集成了XML-RPC扩展,而且该扩展跟xmlrpc扩展无关,能够独立实现XML-RPC的协议交互,如果没有xmlrpc扩展,建议使 用PEAR::XML-RPC扩展。

我们这里主要是以XML-RPC来简单描述Web Service的交互过程,部分内容来自PHP手册,更详细内容,建议参考手册。

[  安装xmlrpc扩展 ]

如果你的系统中没有安装xmlrpc的php扩展,那么请正确安装。

在 Windows平台下,首先把PHP安装目录下的扩展php_xmlrpc.dll放到C:\Windows或者C:\Winnt目录下,(PHP4的扩 展在C:\php\extensions目录中,PHP5的扩展在C:\php\ext目录中),同时在C:\Windows\php.ini或者C: \Winnt\php.ini中把extension=php_xmlrpc.dll前面的分号”;”去掉,然后重启Web服务器后查看 phpinfo()有没有XML-RPC项目就能够确定是否已经正确安装xmlrpc扩展。

在Unix/Linux平台下,如果没有安装xmlrpc扩展,请在重新编译PHP,在configure的时候请加入 –with-xmlrpc 选项,然后查看phpinfo()看是否正常安装xmlrpc。

(注意:以下操作都是建立在xmlrpc扩张正常安装前提下,请务必正确安装。)

[  XML-RPC工作原理 ]

XML-RPC大致就是整个过程就是使用XML来进行通信。首先构造一个RPC 服务器端用来出来从RPC客户端传递过来的使用XML封装的请求,并且把处理结果通过XML的形式返回给RPC客户端,客户端就去分析XML获取自己需要的数据。

XML-RPC的服务器端必须有现成的函数提供给客户端调用,并且客户端提交的请求中的函数和方法必须和服务器端的一致,否则将无法获取所需要的结果。

下面我进行简单的代码来描述整个过程。


[  XML-RPC实践 ]

服务器端使用xmlrpc_server_create函数产生一个服务器端,然后把需要需要暴露的RPC调用接口进行注册,接受RPC客户端POST过来的XML数据,然后进行处理,处理结果通过XML的形式显示给客户端。

代码如下: rpc_server.php

  1. <?php  
  2. /** 
  3. * 函数:提供给RPC客户端调用的函数 
  4. * 参数: 
  5. * $method 客户端需要调用的函数 
  6. * $params 客户端需要调用的函数的参数数组 
  7. * 返回:返回指定调用结果 
  8. */  
  9. function rpc_server_func($method$params) {  
  10. $parameter = $params[0];  
  11.    if ($parameter == “get”)  
  12.    {  
  13.        $return = This data by get method;  
  14.    }  
  15.    else  
  16.    {  
  17.        $return = Not specify method or params;  
  18.    }  
  19.    return $return;  
  20. }  
  21.   
  22. //产生一个XML-RPC的服务器端  
  23. $xmlrpc_server = xmlrpc_server_create();  
  24.   
  25. //注册一个服务器端调用的方法rpc_server,实际指向的是rpc_server_func函数  
  26. xmlrpc_server_register_method($xmlrpc_server“rpc_server”“rpc_server_func”);  
  27.   
  28. //接受客户端POST过来的XML数据  
  29. $request = $HTTP_RAW_POST_DATA;  
  30.   
  31. //执行调用客户端的XML请求后获取执行结果  
  32. $xmlrpc_response = xmlrpc_server_call_method($xmlrpc_server$request, null);  
  33.   
  34. //把函数处理后的结果XML进行输出  
  35. header(Content-Type: text/xml);  
  36. echo $xmlrpc_response;  
  37.   
  38. //销毁XML-RPC服务器端资源  
  39. xmlrpc_server_destroy($xmlrpc_server);  
  40. ?> 

服务器端构造好了,那么再构造我们的RPC客户端。客户端大致通过Socket访问XML-RPC服务器端的80端口,然后把需要调用的RPC接口封装到XML里,通过POST请求提交给RPC服务器端,最后获取服务器端返回结果。

代码如下:rpc_client.php

  1. <?php  
  2. /** 
  3. * 函数:提供给客户端进行连接XML-RPC服务器端的函数 
  4. * 参数: 
  5. * $host  需要连接的主机 
  6. * $port  连接主机的端口 
  7. * $rpc_server XML-RPC服务器端文件 
  8. * $request  封装的XML请求信息 
  9. * 返回:连接成功成功返回由服务器端返回的XML信息,失败返回false 
  10. */  
  11. function rpc_client_call($host$port$rpc_server$request) {  
  12.   
  13.    //打开指定的服务器端  
  14.    $fp = fsockopen($host$port);  
  15.   
  16.    //构造需要进行通信的XML-RPC服务器端的查询POST请求信息  
  17.    $query = “POST $rpc_server HTTP/1.0\nUser_Agent: XML-RPC Client\nHost: “.$host.“\nContent-Type: text/xml\nContent-Length: “.strlen($request).“\n\n”.$request.“\n”;  
  18.   
  19.    //把构造好的HTTP协议发送给服务器,失败返回false  
  20.    if (!fputs($fp$querystrlen($query)))  
  21.    {  
  22.        $errstr = “Write error”;  
  23.        return false;  
  24.    }  
  25.      
  26.    //获取从服务器端返回的所有信息,包括HTTP头和XML信息  
  27.    $contents = ;  
  28.    while (!feof($fp))  
  29.    {  
  30.        $contents .= fgets($fp);  
  31.    }  
  32.   
  33.    //关闭连接资源后返回获取的内容  
  34.    fclose($fp);  
  35.    return $contents;  
  36. }  
  37.   
  38. //构造连接RPC服务器端的信息  
  39. $host  = localhost;  
  40. $port  = 80;  
  41. $rpc_server = /~heiyeluren/rpc_server.php;  
  42.   
  43. //把需要发送的XML请求进行编码成XML,需要调用的方法是rpc_server,参数是get  
  44. $request = xmlrpc_encode_request(rpc_serverget);  
  45.   
  46. //调用rpc_client_call函数把所有请求发送给XML-RPC服务器端后获取信息  
  47. $response = rpc_client_call($host$port$rpc_server$request);  
  48.   
  49. //分析从服务器端返回的XML,去掉HTTP头信息,并且把XML转为PHP能识别的字符串  
  50. $split = <?xml version=“1.0” encoding=“iso-8859-1”?>;  
  51. $xml =  explode($split$response);  
  52. $xml = $split . array_pop($xml);  
  53. $response = xmlrpc_decode($xml);  
  54.   
  55. //输出从RPC服务器端获取的信息  
  56. print_r($response);  
  57.   
  58. ?>  

大致我们上面的例子就是提交一个叫做rpc_server的方法过去,参数是get,然后获取服务器端的返回,服务器端返回的XML数据是:

  1. <?xml version=“1.0” encoding=“iso-8859-1”?>  
  2. <methodResponse>  
  3. <params>  
  4. <param>  
  5.   <value>  
  6.    <string>This data by get method</string>  
  7.   </value>  
  8. </param>  
  9. </params>  
  10. </methodResponse> 

那么我们再通过xmlrpc_decode函数把这个XML编码为PHP的字符串,我们就能够随意处理了,整个Web Service交互完成。

[  结束语 ]

不 管是XML-RPC也好,SOAP也罢,只要能够让我们稳定、安全的进行远程过程的调用,完成我们的项目,那么就算整个Web Service就是成功的。另外,如果可以的话,也可以尝试使用PEAR中的XML-RPC来实现上面类似的操作,说不定会更简单,更适合你使用。

简单的使用XML-RPC进行Web Service交互就完成了,部分代码参考PHP手册,想获取详细信息建议参考手册,如果文章有不正确,请指正。

PHPRPC for JavaScript

PHPRPC for JavaScript
 
PHPRPC 对 JavaScript 的支持是非常早的,最初协议的设计中对数据的编码方式,返回数据的格式以及回调参数这些内容都充分考虑了 JavaScript 的特性。大部分 PHPRPC 用户最初也是把 PHPRPC 作为一个优秀的 Ajax 方案来使用的。但是 PHPRPC for JavaScript 不同于其它那些专门用于 Ajax 的 RPC 方案(如 DWR、xajax 等),PHPRPC for JavaScript 客户端与服务器是松散耦合的,它不依赖于某种特定语言编写的服务器。并且它还可以同目前许多优秀的 Ajax 框架(如 JQuery、YUI、MooTools 等)一起使用,而不会有任何冲突。并且它还有一个最大的好处,那就是可以让你轻松实现跨域调用。
 
 
PHPRPC for JavaScript 的安装
 

PHPRPC for JavaScript 有 2 个版本的实现,一个是纯 JavaScript 实现的版本(js 版本),另一个是 Flash 与 JavaScript 混合实现的版本(ajs 版本1)。

PHPRPC for JavaScript 两个版本的安装使用方法略有不同,我们下面分别来介绍一下。

js 版本的安装

js 目录下是纯 JavaScript 版本的源代码,其中的 compressed 目录下是压缩后的版本,压缩后的版本有 2 个,直接存放在 compressed 目录下的是不兼容 Windows IE 5.0 的版本(但兼容 Windows IE 5.5 及其以上版本),ie5compat 目录下是兼容 Windows IE 5.0 浏览器的版本。通常情况下,您不需要使用 ie5compat 的版本,这并不是因为 ie5compat 版本更大一些,运行效率更低一些。而是因为现在还在使用 IE 5.0 的用户基本上已经不存在了。另一个更重要的原因是你页面中的 HTML 部分可能根本就无法在 IE 5.0 上正常显示,其它的(除了 PHPRPC 以外的)脚本也无法在 IE 5.0 上面正常运行。因为 IE 5.0 对 HTML 的显示和 JavaScript 的支持实在是相当差劲。

你如果要在你的页面中引用 PHPRPC for JavaScript,只需要把 compressed 下的 phprpc_client.js 复制到你的 Web 目录的脚本目录下,然后在你的页面中像引用其它外部脚本一样引用该脚本文件就可以了,引用的代码看上去像下面这样:

  1. <script type=“text/javascript” src=“scripts/phprpc_client.js”></script> 

上面这句,你可以放在 head 中,也可以放在 body 中,只要放在你创建 PHPRPC_Client 对象之前就可以了。

ajs 版本的安装

ajs 目录下是 JavaScript 和 Flash 混合实现版本的源代码。同样,你只需要关心 compressed 下的文件(如果你不打算修改源代码的话)。你需要做的同样是将 phprpc_client.js 复制到你的 Web 目录的脚本目录下,同时把 phprpc_flash.js 也复制过去,而 flashrequest.swf 文件你可以放到 Web 目录下的任何你觉得合适的目录下。然后你需要将 phprpc_flash.js 中的 flashrequest.swf 路径修改为你实际的 Web 路径,修改后的代码可能会像这样:

  1. document.write([‘<object classid=”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″ ‘,  
  2.                 ‘type=”application/x-shockwave-flash” ‘,  
  3.                 ‘codebase=”http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0″ ‘,  
  4.                 ‘width=”0″ height=”0″ id=”flashrequest_as3″>’,  
  5.                 ‘<param name=”movie” value=”/scripts/flashrequest.swf” />’,  
  6.                 ‘<param name=”allowScriptAccess” value=”always” />’,  
  7.                 ‘<param name=”quality” value=”high” />’,  
  8.                 ‘<embed src=”/scripts/flashrequest.swf” type=”application/x-shockwave-flash” ‘,  
  9.                 ‘width=”0″ height=”0″ name=”flashrequest_as3″ allowScriptAccess=”always” />’,  
  10.                 ‘</object>’].join()); 

最后,在你的页面中引用这两个脚本,其中 phprpc_client.js 可以放在 head 或者 body 中,而 phproc_flash.js 需要放到 body 中,但不要放到 form 中。这里 ajs 的意思是 Another JavaScript 的意思,你也可以理解为 ActionScript & JavaScript 的意思。

 
 
 
 
PHPRPC for JavaScript 客户端

PHPRPC for JavaScript 的 js 版本和 ajs 版本除了前面安装部分所介绍的引入方法有所不同之外,在用法上基本没有区别。下面我们先来看一下基本用法。

如何调用 PHPRPC 服务

我们先通过一个简单的例子,来介绍如何调用 PHPRPC 服务。

  1. var client = new PHPRPC_Client(‘http://localhost:8080/index.aspx’, [‘add’‘sub’]);  
  2. client.setKeyLength(256);  
  3. client.setEncryptMode(2);  
  4. client.add(1, 2, function (result, args, output, warning) {  
  5.     alert(result);  
  6. });  
  7. client.sub(1, 2, function (result, args, output, warning) {  
  8.     alert(result);  
  9. }); 

PHPRPC_Client 对象的 setKeyLength setEncryptMode 这两个方法是跟加密传输有关的。

setKeyLength 方法用于设置密钥长度

setEncryptMode 方法用于设置加密模式

上面设置密钥长度、加密模式都是可选项,如果你不需要这些功能,可以直接忽略它们。

PHPRPC 3.0 for JavaScript 客户端与 Java、.NET 客户端不同,它不需要使用 useService 来返回指定接口的远程代理对象,JavaScript 客户端本身就是一个代理对象。所以,上面例子中 client.add client.sub 这两个调用实际上调用的就是远程方法,对于 JavaScript 客户端来说,远程方法名虽然可以不事先声明,但这样只能在 client.onready 事件发生后或者 client.getReady() 等于 true 时才能进行调用,但这种做法是为了保持与旧版本兼容而提供的,属于过时的方法,所以不推荐这种做法,而是强烈建议像上面那样直接在客户端代码中指定所需要调用的远程方法名。

回调函数有四个参数,你可以认为它们是服务器端方法执行之后返回的内容。

第一个参数 result 是服务器端方法(函数)的返回值,它可以是任意类型。

第二个参数 args 是方法调用的参数,如果这个调用是一个引用参数传递的调用,参数也有可能被修改,这时候,你可以通过 args 来获得修改后的参数,关于引用参数传递的调用我们后面会做进一步说明。

第三个参数 output 是服务器端输出的内容,它是字符串类型的。

第四个参数 warning 是服务器端发生的警告错误(目前只有 PHP 服务器会产生警告错误),一般只调试过程中可能会用到。

通过这个例子,我想你已经可以掌握 PHPRPC for JavaScript 客户端的基本使用方法了。

如何在调用 PHPRPC 服务时,进行引用参数传递?

引用参数传递实际上非常简单,看下面这个例子,首先来看 PHP 的服务器端:

  1. <?php  
  2. include(‘phprpc_server.php’);  
  3. function inc(&$n) {  
  4.     $n++;  
  5. }  
  6. $phprpc_server = new PHPRPC_Server();  
  7. $phprpc_server->add(‘inc’);  
  8. $phprpc_server->start();  
  9. ?> 

这个服务器发布了一个 inc 方法,该方法是将参数值加一。这个方法是需要引用参数传递的。下面我们来看看如何在 JavaScript 中调用这个远程过程:

  1. var client = new PHPRPC_Client(‘http://localhost/index.php’, [‘inc’]);  
  2. client.inc(1, function (result, args, output, warning) {  
  3.     alert(args[0]);  
  4. }, true); 

其实很简单,只要在回调函数之后跟一个 true 参数就可以了。这个 true 就是表示启用引用参数传递。

如何来得到远程过程执行的错误信息?

PHPRPC 把错误分为两种,一种是致命错误,一种是警告性错误。

当远程过程执行发生致命错误时,远程过程调用的返回值是一个 PHPRPC_Error 类型的对象,它其中包含了远程过程执行时发生的致命错误信息。

当远程过程执行发生警告性错误时,你可以通过回调函数的第四个参数 warning 得到警告错误,warning 的值也是 PHPRPC_Error 类型的对象。如果没有发生警告错误,warning 为 null