什么是XML_RPC
一个远程过程调用(远端程序呼叫)(remote procedure call,RPC)的分布式计算协议,通过XML将调用函数封装,并使用HTTP协议作为传送机制。
有用特点
压缩:
支持对传递的参数和返回值进行压缩
Streaming Mode
以流的方式传输数据,适合大数据量和快速传输
Handler创建
创建handler对request进行处理,就是拦截器
Cookie Handling
动态代理:
客户端和服务器端使用接口打交道。类似于 CXF的交互方式
系统架构
客户端是一个无状态、线程安全的对象,需要配置一下参数ClientConfig(包含配置属性,如 server URL, credentials, character set.)、TransportFactory(根据配置信息创建对象和服务器端通信)、XMLWriterFactory(创建xml,通常不需要关注)
服务端 用于接收客户端请求,可以嵌入在servlet container如tomcat,或者作为main函数单独运行,需要配置 XmlRpcServerConfigImple对象
认证
支持用户名和密码的认证方式
客户端
在XmlRpcClientConfigImpl对象中配置 basicUserName和basicPassword 。
服务器端
在tomcat 中运行时:
重写XmlRpcServlet的 newXmlRpcHandlerMapping()方法,创建XmlRpcHandler的实例,得到 XmlRpcRequest.getConfig()返回的XmlRpcRequestConfig对象,通过getBasicUserName()和getBasicPassword()获得信息 如下所示
public class MyServlet extends XmlRpcServlet {
private boolean isAuthenticated(String pUserName, String pPassword) {
return "foo".equals(pUserName) && "bar".equals(pPassword);
}
protected XmlRpcHandlerMapping newXmlRpcHandlerMapping() throws XmlRpcException {
PropertyHandlerMapping mapping
= (PropertyHandlerMapping) super.newXmlRpcHandlerMapping();
AbstractReflectiveHandlerMapping.AuthenticationHandler handler =
new AbstractReflectiveHandlerMapping.AuthenticationHandler(){
public boolean isAuthorized(XmlRpcRequest pRequest){
XmlRpcHttpRequestConfig config =
(XmlRpcHttpRequestConfig) pRequest.getConfig();
return isAuthenticated(config.getBasicUserName(),
config.getBasicPassword());
};
};
mapping.setAuthenticationHandler(handler);
return mapping;
}
}
SSL 加密
支持,可能配置有点复杂,具体请参考:http://ws.apache.org/xmlrpc/ssl.html
服务器端: keytool -export -alias tomcat -rfc -file tomcat.crt
客户端:keytool -import -alias servercert -file tomcat.crt -keystore truststore
简单示例
客户端
功能:调用Calculator.add,并传递参数 2,3
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://127.0.0.1:8080/xmlrpc"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Object[] params = new Object[]{new Integer(33), new Integer(9)};
Integer result = (Integer) client.execute("Calculator.add", params);
服务器端
1. 创建业务类,上面就是创建一个 Calculatro类,其中有 public int add(int a,int b)方法。
2. 创建属性文件 XmlRpcServlet.properties ,放在jar文件的 org.apache.xmlrpc.webserver包中。
Calculator =org.apache.xmlrpc.demo.Calculator
3. 在web.xml中加入
<servlet>
<servlet-name>XmlRpcServlet</servlet-name>
<servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class>
<init-param>
<param-name>enabledForExtensions</param-name>
<param-value>true</param-value>
<description>
Sets, whether the servlet supports vendor extensions for XML-RPC.
</description>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>XmlRpcServlet</servlet-name>
<url-pattern>/xmlrpc</url-pattern>
</servlet-mapping>
数据格式
url格式
参数
POST /xmlrpc HTTP/1.1
Content-Type: text/xml
User-Agent: Apache XML RPC 3.0 (Jakarta Commons httpclient Transport)
Host: 135.252.156.147:8080
Content-Length: 260
<?xmlversion="1.0"encoding="UTF-8"?>
<methodCallxmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<methodName>Calculator.add</methodName>
<params>
<param>
<value>
<i4>2</i4>
</value>
</param>
<param>
<value>
<i4>3</i4>
</value>
</param>
</params>
</methodCall>
第一行的URI(/RPC2)格式不是特定的。可以为空,如果服务器只处理XML-RPC请求甚至可以只是简单的一个斜线。可是,如果服务器除了XML-RPC外还提供其他的HTTP请求,URI可以帮助我们把请求指向特定的XML-RPC服务。
User-Agent和Host项是必须的。
Content-Type的值必须是text/xml.
Content-Length必须指定,而且必须是正确的值。
返回值
HTTP/1.1 200 OK
Server: Apache XML-RPC 1.0
Connection: close
Content-Type: text/xml
Content-Length: 189
<?xmlversion="1.0"encoding="UTF-8"?>
<methodResponsexmlns:ex="http://ws.apache.org/xmlrpc/namespaces/extensions">
<params>
<param>
<value>
<i4>5</i4>
</value>
</param>
</params>
</methodResponse>
说明
其格式很简单,几乎是不言自明的,分别用methodCall和methodResponse标签标识发送给Server的调用请求和Server的返回结果,请求方法的名称用methodName标识,参数用params和param标识,而参数的类型标签则如下表所示:
Tag | Java Type | 说明 |
<i4> or <int> | Integer/int | 4字节带符号整数值 |
<boolean> | Boolean | 0 (false) or 1 (true) |
<string> | String | 字符串 |
<double> | Double | 双精度带符号浮点值 |
<dateTime.iso8601> | java.util.Date | 日期/时间 |
<base64> | byte[] | base64编码的二进制数据 |
<struct> | java.util.Map | 键值对,键为String类型,而值为任意有效类型 |
<array> | Object[] java.util.List | 对象数组 |
与其他语言通讯
感觉好像只要遵守相应的规范就可以了,比如使用 apache xml应该就算遵守规范了
认证与安全
客户端每次调用将用户名密码写入XML-RPC调用的header中进行传递,示例如下:
POST /xmlrpc HTTP/1.1
Content-Type: text/xml
User-Agent: Apache XML RPC 3.1.3(Jakarta Commons httpclient Transport)
Authorization: Basic dGVzdDpzZWNyZXRl
Host: 127.0.0.1:8888
Content-Length: 260
其中Authorization: Basic dGVzdDpzZWNyZXRl指定了认证方式,Basic为不变的基本关键字。dGVzdDpzZWNyZXRl是test:secrete的Base64编码,dGVzdDpzZWNyZXRl经过Base64解码后可以解码为test:secrete也就是用户名:密码的形式。
服务端对http header进行解析后处理Authorization信息,确定是否对这个请求通过。
对于资源接入的设备来说,可以根据需要自行决定是否提供https协议进行XML-RPC调用。
参考
XML-RPC标准请参见http://xmlrpc.scripting.com/default.html
Java XML-RPC实现请参见 http://ws.apache.org/xmlrpc/
C/C++ XML-RPC实现请参见:http://xmlrpc-c.sourceforge.net/
Python XML-RPC实现请参见: http://docs.python.org/library/xmlrpclib.html