PHP写WebService
PHP中很少用到WebService,最近才研究了一下,似乎没有想象中复杂。
1、Server端
定义一个类,在其中实现方法,然后用SoapServer将此类发布出去。
data_service.php:
- <?php
- class DataAction{
- public function add($x, $y){
- return $x + $y;
- }
- }
- //定义SoapServer,不指定wsdl,必须指定uri,相当于asmx中的namespace
- $server = new SoapServer(null, ["uri" => "php.test"]);
- //指定此SoapServer发布DataAction类中的所有方法
- $server->setClass("DataAction");
- $server->handle>
- ?>
也可以不用class,直接发布function。
- <?php
- function add($x, $y){
- return $x + $y;
- }
- $server = new SoapServer(null, ["uri" => "php.test"]);
- $server->addFunction("add");
- $server->handle();
- ?>
2、Client端
client.php:
- <?php
- //SoapClient即WebService客户端,其uri与Server端保持一致,location是WebService服务地址
- $client = new SoapClient(null, ["uri" => "php.test", "location" => "http://192.168.90.81/test/data_service.php"]);
- //调用add方法,传入参数
- echo $client->add(100, 200);
- unset($client);
- ?>
抓包看看:
- 请求包:
- POST /test/data_service.php HTTP/1.1
- Host: 192.168.90.81
- Connection: Keep-Alive
- User-Agent: PHP-SOAP/5.4.3
- Content-Type: text/xml; charset=utf-8
- SOAPAction: "php.test#add"
- Content-Length: 512
- <?xml version="1.0" encoding="UTF-8"?>
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="php.test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:add><param0 xsi:type="xsd:int">100</param0><param1 xsi:type="xsd:int">800</param1></ns1:add></SOAP-ENV:Body></SOAP-ENV:Envelope>
- --------------------------------
- 响应包:
- HTTP/1.1 200 OK
- Server: nginx/1.2.0
- Date: Thu, 07 Jun 2012 06:51:33 GMT
- Content-Type: text/xml; charset=utf-8
- Content-Length: 488
- Connection: keep-alive
- X-Powered-By: PHP/5.4.3
- <?xml version="1.0" encoding="UTF-8"?>
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="php.net" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:addResponse><return xsi:type="xsd:int">900</return></ns1:addResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
需要注意,如果PHP是以FastCGI方式运行,且只启动了一个进程 ,由于php-cgi.exe的单线程模型,访问client.php时其又会向data_service.php发送请求,但当前请求未处理完毕,data_service.php无法响应,会造成卡死得不到结果。
比如nginx如果没有使用负载均衡,所有php请求都转发到同一个php-cgi进程,就肯定会卡死。请负载均衡到不同进程上,或者换用isapi模式。
使用这种方式没有定义wsdl,没想明白双方是如何约定通讯的。另外显然,用这种方式肯定无法跨语言访问服务,因为我们访问data_service.php?wsdl拿不到wsdl,返回如下:
- <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
- <SOAP-ENV:Body>
- <SOAP-ENV:Fault>
- <faultcode>SOAP-ENV:Server</faultcode>
- <faultstring>WSDL generation is not supported yet</faultstring>
- </SOAP-ENV:Fault>
- </SOAP-ENV:Body>
- </SOAP-ENV:Envelope>