XML-RPC 协议是现在大多数 blog 站点支持的标准协议。通过使用该协议,我们可以很方便地使用离线编辑客户端编辑好文章,然后直接上传到 blog 系统进行发布。豆子目前正在进行的一个项目,OrbitsWriter 就是做得类似的工作。尽管完成度不高,但是 XML-RPC 一节已经调通。如果对该项目有任何建议或意见,可以在 GitHub 上找到项目地址。
本文所叙述的实现,即是豆子用在 OrbitsWriter 中的代码。如果需要,完全可以很方便直接从中分离开来。希望这里描述的一种实现,能够对更多的项目有所帮助。
首先来介绍一下 XML-RPC 协议。XML-RPC 是一个通过 Internet 进行的远程过程调用协议。每一个 XML-RPC 消息都是一个 HTTP-POST 请求;请求体则是 XML 格式的。过程在服务器上执行,其返回值同样是 XML 格式。这意味着,我们需要使用 QtNetwork 和 QtXml 两个模块来实现这个客户端。
XML-RPC 协议的过程参数应该是标量,例如数字、字符串、日期等,也可以是复杂的结构体或者数组等。
XML-RPC 请求
下面是一个合法的 XML-RPC 请求:
POST /RPC2 HTTP/1.0 User-Agent: Frontier/5.1.2 (WinNT) Host: betty.userland.com Content-Type: text/xml Content-length: 181 <?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall>
请求头
请求头的第一行 URI 的格式并没有指定:可以是空的,可以只有一个斜线(当服务器仅处理 XML-RPC 调用时)。不过,普遍情况应该是服务器处理很多类型的 HTTP 请求。在这种情况下,我们就得利用这个 URI 识别出,这个请求应该由 XML-RPC 处理代码进行处理。在这个例子中,URI 是 /RPC2,也就是说,需要将这个请求分发给 RPC2 这个响应函数。
User-Agent 和 Host 必须指定。
Content-Type 必须是 text/xml。
Content-Length 必须指定,并且必须是正确的。
有效信息格式
有效信息以 XML 的格式发送,其根标签是<methodCall>
。
<methodCall>
必须包含一个<methodName>
子项,类型是一个字符串,包含需要调用的函数名称。这个字符串只能包含可识别字符:大写和小写的 A-Z,数字 0-9,下划线,点号,冒号和斜线。这个名字由服务器进行解释。例如,methodName 可以是包含可执行代码的脚本文件的文件名,可以是数据库表的单元格名,也可以是包含了子目录和子文件的文件夹名。
如果过程调用需要参数,<methodCall>
必须包含一个<params>
子项。<params>
则包含若干<param>
子项,每一个<param>
都要有一个<value>
标签。
<value>
<value>
可以是任何标量,类型允许嵌套。合法的子标签如下表所示:
标签 | 类型 | 示例 |
<i4> 或者<int> | 四字节有符号整数 | -12 |
<boolean> | 0 (false) 或者 1 (true) | 1 |
<string> | 字符串 | hello world |
<double> | 双精度有符号浮点数 | -12.214 |
<dateTime.iso8601> | 日期/时间 | 19980717T14:08:55 |
<base64> | base64 编码的二进制数据 | eW91IGNhbid0IHJlYWQgdGhpcyE= |
如果不能识别该类型,则当做 string 处理。
<struct>
值类型也可以是<struct>
。
<struct>
标签包含若干<member>
,每一个<member>
都要有一个<name>
和一个<value>
。
下面是拥有两个元素的<struct>
:
<struct> <member> <name>lowerBound</name> <value><i4>18</i4></value> </member> <member> <name>upperBound</name> <value><i4>139</i4></value> </member> </struct>
<struct>
可以嵌套。任何<value>
都可以包含另外的<struct>
或者其它类型,包括下面介绍的<array>
。
<array>
值类型也可以是<array>
。<array>
包含一个<data>
子标签,<data>
则包含若干个<value>
。
例如,下面的示例是一个包含了四个元素的数组:
<array> <data> <value><i4>12</i4></value> <value><string>Egypt</string></value> <value><boolean>0</boolean></value> <value><i4>-31</i4></value> </data> </array>
<array> 标签没有名字。
正如上面的代码所示,我们可以将不同类型的数据组装成一个数组。
<arrays>
也可以嵌套,任何值都可以包含<array>
或其它类型,包括<struct>
。
XML-RPC 响应
下面是一个合法的 XML-RPC 响应:
HTTP/1.1 200 OK Connection: close Content-Length: 158 Content-Type: text/xml Date: Fri, 17 Jul 1998 19:55:08 GMT Server: UserLand Frontier/5.1.2-WinNT <?xml version="1.0"?> <methodResponse> <params> <param> <value><string>South Dakota</string></value> </param> </params> </methodResponse>
响应格式
第一行,除非有其它服务器错误,返回值总是 200 OK。
Content-Type 是 text/xml。Content-Length 必须指定,并且是正确的。
响应体是一个 XML 结构,根标签是<methodResponse>
,包含一个<params>
标签,该标签又包含一个<value>
。
<methodResponse>
也可能包含一个<fault>
标签,这个<fault>
包含一个<value>
,该标签是一个<struct>
,包含两个元素:<faultCode>
,<int>
类型以及<faultString>
,<string>
类型。
<methodResponse>
不允许同时包含<fault>
和<params>
。
<fault> 示例
HTTP/1.1 200 OK Connection: close Content-Length: 426 Content-Type: text/xml Date: Fri, 17 Jul 1998 19:55:02 GMT Server: UserLand Frontier/5.1.2-WinNT <?xml version="1.0"?> <methodResponse> <fault> <value> <struct> <member> <name>faultCode</name> <value><int>4</int></value> </member> <member> <name>faultString</name> <value><string>Too many parameters.</string></value> </member> </struct> </value> </fault> </methodResponse>