usoap是PHP环境中的开源soap工具,算是用得比较多的一个工具了。
在utf-8环境中,nusoap可以工作得很好。但是当用于中文环境中时,nusoap经常会出现一些让人不得其解的问题。
最近一个项目中,服务端是用nusoap实现的,支持UTF-8和GBK两种字符集。
当客户端用GBK来调用服务时,出现错误:Charset from HTTP Content-Type US-ASCII does not match encoding from XML declaration GBK,意思是说,客户端的请求中,HTTP Content-Type的字符集是US-ASCII,而soap请求的XML声明里,字符集是GBK,两者不匹配。检查soap client的request变量,HTTP Content-Type的值也是GBK,怎么会变成了US-ASCII呢?有点莫名其妙了。于是只好跟踪nusoap的源码,发现nusoap在处理HTTP Content-Type时把US-ASCII,ISO-8859-1,UTF-8以外的字符集都默认为US-ASCII。最终发现其原因是因为nusoap使用了xml parser,而xml parser只支持这几种字符集。所以客户端在调用时,当采用GBK编时,调用的HTTP Content-Type 和 soap request的字符集都应该换成ISO-8859-1。
稍后在封装客户端时,也遇到一个类似的问题。客户端字符集声明为GBK,服务端在返回SOAP调用结果时 HTTP Content-Type和soap request都声明字符集为GBK,客户端没有获取任何值。查看soap client的response对象,发现服务端返回正确。为解决这个问题,只好修改服务端,把HTTP Content-Type和soap response的字符集都声明为ISO-8859-1。
所以在使用nusoap时,当遇到GBK或GB2312字符集时,可以使用ISO-8859-1代替。
=============================================================================================
PHP Web Service Server端:
<?php //header("Content-Type:text/html;charset=UTF-8"); // Pull in the NuSOAP code require_once('./lib/nusoap.php'); // Define the method as a PHP function function hello($name) { return '你好! ' . $name; } // Create the server instance $server = new soap_server; $server->configureWSDL('hellowsdl', 'urn:hellowsdl'); $server->wsdl->schemaTargetNamespace = 'urn:hellowsdl'; // Register the method to expose $server->register('hello', array('name'=>'xsd:string'), array('return'=>'xsd:string'), 'urn:hellowsdl', 'urn:hellowsdl#hello', 'rpc', 'encoded', 'Say hello to somebody' ); // Use the request to (try to) invoke the service $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : ''; $server->service($HTTP_RAW_POST_DATA); ?>
Client 端:
<?php //header("Content-Type:text/html;charset=GB2312"); // Pull in the NuSOAP code require_once('./lib/nusoap.php'); // Create the client instance $client = new soapclient('http://localhost/soapTest/helloService.php?wsdl',true); // Call the SOAP method $param = array("name"=>"安迪"); $result = $client->call('hello', $param); // Display the result //print_r($result); if(!$err=$client->getError()){ print_r($result ); print('</br>'); echo "程序返回: ", htmlentities($result,ENT_QUOTES,GB2312); } else{ echo "错误: ", htmlentities($result,ENT_QUOTES,GB2312); } echo ' <h2> Request </h2> <pre> ' . htmlspecialchars($client-> request, ENT_QUOTES,GB2312) . ' </pre> '; echo ' <h2> Response </h2> <pre> ' . htmlspecialchars($client-> response, ENT_QUOTES,GB2312) . ' </pre> '; echo ' <h2> Debug </h2> <pre> ' . htmlspecialchars($client-> debug_str, ENT_QUOTES,GB2312) . ' </pre> '; ?>
Java代码:
注意: 要使用Axis1.x, 去官网不要下载了Axis2。好像Axis1.x 和 Axis2还是差别很大的,而且目前Axis1.x的文档比较全点。这些是网上搜到的说法。
如果需要使用中文参数调用Web Service,必须使用ISO-8859-1编码参数,返回的Response再解码。不要使用别的编码,会出错!
import org.apache.axis.client.Service;
import org.apache.axis.client.Call;
public class WebServiceTest {
public static void main(String[] args) {
String endpoint = "http://localhost/soapTest/helloService.php";
//String endpoint = "http://testweb.dev.php/testWebService/testWebService.php";//该段就是上面刚将的地址
Service service = new Service();
Call call;
try {
call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("hello");
String param = new String("安迪".getBytes(),"ISO-8859-1");//如果没有加这段,中文参数将会乱码
//String param = new String("中文");
String s = (String) call.invoke(new Object[] {param});
s = new String(s.getBytes("ISO-8859-1"));//如果没有转换编码,中文也会乱码
System.out.println(s);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}