xmlrpc.client --- XML-RPC 客户端访问¶
源代码: Lib/xmlrpc/client.py
XML-RPC 是一种远程过程调用方法,它以使用 HTTP(S) 传递的 XML 作为载体。 通过它,客户端可以在远程服务器(服务器以 URI 指明)上调用带参数的方法并获取结构化的数据。 本模块支持编写 XML-RPC 客户端代码;它会处理在通用 Python 对象和 XML 之间进行在线翻译的所有细节。
警告
xmlrpc.client 模块对于恶意构建的数据是不安全的。 如果你需要解析不受信任或未经身份验证的数据,请参阅 XML 安全。
在 3.5 版本发生变更: 对于 HTTPS URI,现在 xmlrpc.client 默认会执行所有必要的证书和主机名检查。
Availability: not WASI.
此模块在 WebAssembly 平台上无效或不可用。 请参阅 WebAssembly 平台 了解详情。
- class xmlrpc.client.ServerProxy(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False, use_builtin_types=False, *, headers=(), context=None)¶
ServerProxy实例是管理与远程 XML-RPC 服务器通信的对象。 要求的第一个参数为 URI (统一资源定位符),通常就是服务器的 URL。 可选的第二个参数为传输工厂实例;在默认情况下对于 https: URL 是一个内部SafeTransport实例,在其他情况下则是一个内部 HTTPTransport实例。 可选的第三个参数为编码格式,默认为 UTF-8。 可选的第四个参数为调试旗标。下列形参控制所返回代理实例的使用。 如果 allow_none 为真值,则 Python 常量
None将被转写至 XML;默认行为是针对None引发TypeError。 这是对 XML-RPC 规格的一个常用扩展,但并不被所有客户端和服务器所支持;请参阅 http://ontosys.com/xml-rpc/extensions.php 了解详情。 use_builtin_types 旗标可被用来将日期/时间值表示为datetime.datetime对象而将二进制数据表示为bytes对象;此旗标默认为假值。datetime.datetime,bytes和bytearray对象可以被传给调用操作。 headers 形参为可选的随每次请求发送的 HTTP 标头序列,其形式为包含代表标头名称和值的 2 元组序列。 (例如[('Header-Name', 'value')])。 如果提供了 HTTPS URL,则 context 可以为ssl.SSLContext并配置底层 HTTPS 连接的 SSL 设置。 已过时的 use_datetime 旗标与 use_builtin_types 类似但它只适用于日期/时间值。在 3.3 版本发生变更: 增加了 use_builtin_types 旗标。
在 3.8 版本发生变更: 增加了 headers 形参。
HTTP 和 HTTPS 传输均支持用于 HTTP 基本身份验证的 URL 语法扩展:
http://user:pass@host:port/path。user:pass部分将以 base64 编码为 HTTP 'Authorization' 标头,并在唤起 XML-RPC 方法时作为连接过程的一部分发送给远程服务器。 你只需要在远程服务器要求基本身份验证用户名和密码时使用此语法。返回的实例是一个代理对象,具有可被用来在远程服务器上发起相应 RPC 调用的方法。 如果远程服务器支持内省 API,则也可使用该代理对象在远程服务器上查询它所支持的方法(服务发现)并获取其他服务器相关的元数据
适用的类型(即可通过 XML 生成 marshall 对象),包括如下类型(除了已说明的例外,它们都会被反 marshall 为同样的 Python 类型):
XML-RPC类型
Python 类型
booleanint,i1,i2,i4,i8或者bigintegerint的范围从 -2147483648 到 2147483647。值将获得<int>标志。double或floatfloat。值将获得<double>标志。stringarraystructdict。 键必须为字符串,值可以为任何适用的类型。 可以传入用户自定义类的对象;只有其__dict__属性会被传输。dateTime.iso8601DateTime或datetime.datetime。返回的类型取决于 use_builtin_types 和 use_datetime 标志的值。base64nilNone常量。仅当 allow_none 为true时才允许传递。bigdecimaldecimal.Decimal. 仅返回类型。这是This is the full set of data types supported by XML-RPC 所支持数据类型的完整集合。 方法调用也可能引发一个特殊的
Fault实例,用来提示 XML-RPC 服务器错误,或是用ProtocolError来提示 HTTP/HTTPS 传输层中的错误。Fault和ProtocolError都派生自名为Error的基类。 请注意 xmlrpc client 模块目前不可 marshal 内置类型的子类的实例。当传入字符串时,XML 中的特殊字符如
<,>和&将被自动转义。 但是,调用方有责任确保字符串中没有 XML 中不允许的字符,例如 ASCII 值在 0 和 31 之间的控制字符(当然,制表、换行和回车除外);不这样做将导致 XML-RPC 请求的 XML 格式不正确。 如果你必须通过 XML-RPC 传入任意字节数据,请使用bytes或bytearray类或者下文描述的Binary包装器类。Server被保留作为ServerProxy的别名用于向下兼容。 新的代码应当使用ServerProxy。在 3.5 版本发生变更: 增加了 context 参数。
在 3.6 版本发生变更: 增加了对带有前缀的类型标签的支持 (例如
ex:nil)。 增加了对反 marshall 被 Apache XML-RPC 实现用于表示数值的附加类型的支持:i1,i2,i8,biginteger,float和bigdecimal。 请参阅 https://ws.apache.org/xmlrpc/types.html 了解详情。
参见
- XML-RPC HOWTO
以多种语言对 XML-RPC 操作和客户端软件进行了很好的说明。 包含 XML-RPC 客户端开发者所需知道的几乎任何事情。
- XML-RPC Introspection
描述了用于内省的 XML-RPC 协议扩展。
- XML-RPC Specification
官方规范说明。
ServerProxy 对象¶
A ServerProxy instance has a method corresponding to each remote
procedure call accepted by the XML-RPC server. Calling the method performs an
RPC, dispatched by both name and argument signature (e.g. the same method name
can be overloaded with multiple argument signatures). The RPC finishes either
by returning data in a conformant type or by raising a Fault or
ProtocolError exception indicating an error.
支持 XML 内省 API 的服务器还支持一些以保留的 system 属性分组的通用方法:
- ServerProxy.system.listMethods()¶
此方法返回一个字符串列表,每个字符串都各自对应 XML-RPC 服务器所支持的(非系统)方法。
- ServerProxy.system.methodSignature(name)¶
此方法接受一个形参,即某个由 XML-RPC 服务器所实现的方法名称。 它返回一个由此方法可能的签名组成的数组。 一个签名就是一个类型数组。 这些类型中的第一个是方法的的返回类型,其余的均为形参。
由于允许多个签名(即重载),此方法是返回一个签名列表而非一个单例。
签名本身被限制为一个方法所期望的最高层级形参。 举例来说如果一个方法期望有一个结构体数组作为形参,并返回一个字符串,则其签名就是 "string, array"。 如果它期望有三个整数并返回一个字符串,则其签名是 "string, int, int, int"。
如果方法没有定义任何签名,则将返回一个非数组值。 在 Python 中这意味着返回值的类型为列表以外的类型。
- ServerProxy.system.methodHelp(name)¶
此方法接受一个形参,即 XML-RPC 服务器所实现的某个方法的名称。 它返回描述相应方法用法的文档字符串。 如果没有可用的文档字符串,则返回空字符串。 文档字符串可以包含 HTML 标记。
在 3.5 版本发生变更: ServerProxy 的实例支持 context manager 协议用于关闭下层传输。
以下是一个可运行的示例。 服务器端代码:
from xmlrpc.server import SimpleXMLRPCServer
def is_even(n):
return n % 2 == 0
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()
前述服务器的客户端代码:
import xmlrpc.client
with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
print("3 is even: %s" % str(proxy.is_even(3)))
print("100 is even: %s" % str(proxy.is_even(100)))
DateTime 对象¶
- class xmlrpc.client.DateTime¶
该类的初始化可以使用距离 Unix 纪元的秒数、时间元组、ISO 8601 时间/日期字符串或
datetime.datetime实例。 它具有下列方法,主要是为 marshall 和反 marshall 代码的内部使用提供支持:- decode(string)¶
接受一个字符串作为实例的新时间值。
它还通过
富比较和__repr__()方法来支持特定的 Python 内置运算符。
以下是一个可运行的示例。 服务器端代码:
import datetime
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def today():
today = datetime.datetime.today()
return xmlrpc.client.DateTime(today)
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(today, "today")
server.serve_forever()
前述服务器的客户端代码:
import xmlrpc.client
import datetime
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
today = proxy.today()
# 将 ISO8601 字符串转换为日期时间对象
converted = datetime.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print("Today: %s" % converted.strftime("%d.%m.%Y, %H:%M"))
Binary 对象¶
- class xmlrpc.client.Binary¶
该类的初始化可以使用字节数据(可包括 NUL)。 对
Binary对象的初始访问是由一个属性来提供的:Binary对象具有下列方法,支持这些方法主要是供 marshall 和反 marshall 代码在内部使用:- encode(out)¶
将此二进制条目的 XML-RPC base 64 编码格式写入到 out 流对象。
被编码数据将依据 RFC 2045 第 6.8 节 每 76 个字符换行一次,这是撰写 XML-RPC 规范说明时 base64 规范的事实标准。
该二进制对象的示例用法。 我们将通过 XMLRPC 来传输一张图片:
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def python_logo():
with open("python_logo.jpg", "rb") as handle:
return xmlrpc.client.Binary(handle.read())
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(python_logo, 'python_logo')
server.serve_forever()
客户端会获取图片并将其保存为一个文件:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
with open("fetched_python_logo.jpg", "wb") as handle:
handle.write(proxy.python_logo().data)
Fault 对象¶
- class xmlrpc.client.Fault¶
Fault对象封装了 XML-RPC fault 标签的内容。 Fault 对象具有下列属性:- faultCode¶
一个指明 fault 类型的整数。
- faultString¶
一个包含与 fault 相关联的诊断消息的字符串。
在接下来的示例中我们将通过返回一个复数类型的值来故意引发一个 Fault。 服务器端代码:
from xmlrpc.server import SimpleXMLRPCServer
# 将发生 marshall 操作错误因为我们将返回一个复数
def add(x, y):
return x+y+0j
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(add, 'add')
server.serve_forever()
前述服务器的客户端代码:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
try:
proxy.add(2, 5)
except xmlrpc.client.Fault as err:
print("A fault occurred")
print("Fault code: %d" % err.faultCode)
print("Fault string: %s" % err.faultString)
ProtocolError 对象¶
- class xmlrpc.client.ProtocolError¶
ProtocolError对象描述了下层传输层中的协议错误(例如当 URI 所指定的服务器不存在时的 404 'not found' 错误)。 它具有下列属性:- url¶
触发错误的 URI 或 URL。
- errcode¶
错误代码。
- errmsg¶
错误消息或诊断字符串。
- headers¶
一个包含触发错误的 HTTP/HTTPS 请求的标头的字典。
在接下来的示例中我们将通过提供一个无效的 URI 来故意引发一个 ProtocolError:
import xmlrpc.client
# 创建一个 ServerProxy,所用 URI 不与 XMLRPC 请求对应
proxy = xmlrpc.client.ServerProxy("http://google.com/")
try:
proxy.some_method()
except xmlrpc.client.ProtocolError as err:
print("A protocol error occurred")
print("URL: %s" % err.url)
print("HTTP/HTTPS headers: %s" % err.headers)
print("Error code: %d" % err.errcode)
print("Error message: %s" % err.errmsg)
MultiCall 对象¶
MultiCall 对象提供了一种将对远程服务器的多个调用封装为一个单独请求的方式 [1]。
- class xmlrpc.client.MultiCall(server)¶
创建一个用于盒式方法调用的对象。 server 是调用的最终目标。 可以针对结果对象被唤起,但它们将立即返回
None,并只在MultiCall对象中存储调用名称和形参。 调用该对象本身会导致所有已存储的调用作为一个单独的system.multicall请求被发送。 此调用的结果是一个 generator;迭代这个生成器会产生各个结果。
以下是该类的用法示例。 服务器端代码:
from xmlrpc.server import SimpleXMLRPCServer
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
return x // y
# 一个带有简单算术函数的简单服务器
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()
前述服务器的客户端代码:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()
print("7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d" % tuple(result))
便捷函数¶
- xmlrpc.client.dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)¶
将 params 转换为一个 XML-RPC 请求,或者当 methodresponse 为真值时转换为一个请求。 params 可以是一个参数元组或一个
Fault异常类的实例。 如果 methodresponse 为真值,则只能返回单个值,这意味着 params 的长度必须为 1。 如果提供了 encoding,则会在生成的 XML 中使用该编码格式;默认值为 UTF-8。 Python 的None值不可在标准 XML-RPC 中使用;要通过扩展来允许使用它,请为 allow_none 提供真值。
- xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)¶
将一个 XML-RPC 请求或响应转换为 Python 对象
(params, methodname)。 params 是一个参数元组;methodname 是一个字符串,或者如果数据包没有提供方法名则为None。 如果 XML-RPC 数据包是代表一个故障条件,则此函数将引发一个Fault异常。 use_builtin_types 旗标可被用于将日期/时间值表示为datetime.datetime对象并将二进制数据表示为bytes对象;此旗标默认为假值。已过时的 use_datetime 旗标与 use_builtin_types 类似但只作用于日期/时间值。
在 3.3 版本发生变更: 增加了 use_builtin_types 旗标。
客户端用法的示例¶
# 简单的测试程序(来自 XML-RPC 规范说明)
from xmlrpc.client import ServerProxy, Error
# server = ServerProxy("http://localhost:8000") # 本地服务器
with ServerProxy("http://betty.userland.com") as proxy:
print(proxy)
try:
print(proxy.examples.getStateName(41))
except Error as v:
print("ERROR", v)
要通过 HTTP 代理访问一个 XML-RPC 服务器,你必须自行定义一个传输。 下面的例子演示了具体做法:
import http.client
import xmlrpc.client
class ProxiedTransport(xmlrpc.client.Transport):
def set_proxy(self, host, port=None, headers=None):
self.proxy = host, port
self.proxy_headers = headers
def make_connection(self, host):
connection = http.client.HTTPConnection(*self.proxy)
connection.set_tunnel(host, headers=self.proxy_headers)
self._connection = host, connection
return connection
transport = ProxiedTransport()
transport.set_proxy('proxy-server', 8080)
server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport)
print(server.examples.getStateName(41))
客户端与服务器用法的示例¶
备注