xmlrpc.client
--- XML-RPC 客戶端訪問?
源代碼: Lib/xmlrpc/client.py
XML-RPC 是一種遠(yuǎn)程過程調(diào)用方法,它以使用 HTTP(S) 傳遞的 XML 作為載體。 通過它,客戶端可以在遠(yuǎn)程服務(wù)器(服務(wù)器以 URI 指明)上調(diào)用帶參數(shù)的方法并獲取結(jié)構(gòu)化的數(shù)據(jù)。 本模塊支持編寫 XML-RPC 客戶端代碼;它會(huì)處理在通用 Python 對(duì)象和 XML 之間進(jìn)行在線翻譯的所有細(xì)節(jié)。
警告
xmlrpc.client
模塊對(duì)于惡意構(gòu)建的數(shù)據(jù)是不安全的。 如果你需要解析不受信任或未經(jīng)身份驗(yàn)證的數(shù)據(jù),請(qǐng)參閱 XML 漏洞。
在 3.5 版更改: 對(duì)于 HTTPS URI,現(xiàn)在 xmlrpc.client
默認(rèn)會(huì)執(zhí)行所有必要的證書和主機(jī)名檢查。
- 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
實(shí)例是管理與遠(yuǎn)程 XML-RPC 服務(wù)器通信的對(duì)象。 要求的第一個(gè)參數(shù)為 URI (統(tǒng)一資源定位符),通常就是服務(wù)器的 URL。 可選的第二個(gè)參數(shù)為傳輸工廠實(shí)例;在默認(rèn)情況下對(duì)于 https: URL 是一個(gè)內(nèi)部SafeTransport
實(shí)例,在其他情況下則是一個(gè)內(nèi)部 HTTPTransport
實(shí)例。 可選的第三個(gè)參數(shù)為編碼格式,默認(rèn)為 UTF-8。 可選的第四個(gè)參數(shù)為調(diào)試旗標(biāo)。下列形參控制所返回代理實(shí)例的使用。 如果 allow_none 為真值,則 Python 常量
None
將被轉(zhuǎn)寫為 XML;默認(rèn)行為是針對(duì)None
引發(fā)TypeError
。 這是對(duì) XML-RPC 規(guī)格的一個(gè)常用擴(kuò)展,但并不被所有客戶端和服務(wù)器所支持;請(qǐng)參閱 http://ontosys.com/xml-rpc/extensions.php 了解詳情。 use_builtin_types 旗標(biāo)可被用來將日期/時(shí)間值表示為datetime.datetime
對(duì)象而將二進(jìn)制數(shù)據(jù)表示為bytes
對(duì)象;此旗標(biāo)默認(rèn)為假值。datetime.datetime
,bytes
和bytearray
對(duì)象可以被傳給調(diào)用操作。 headers 形參為可選的隨每次請(qǐng)求發(fā)送的 HTTP 標(biāo)頭序列,其形式為包含代表標(biāo)頭名稱和值的 2 元組的序列 (例如 [('Header-Name', 'value')])。 已不再適用的 use_datetime 旗標(biāo)與 use_builtin_types 類似但它只針對(duì)日期/時(shí)間值。
在 3.3 版更改: 增加了 use_builtin_types 旗標(biāo)。
在 3.8 版更改: 增加了 headers 形參。
HTTP 和 HTTPS 傳輸均支持用于 HTTP 基本身份驗(yàn)證的 URL 語(yǔ)法擴(kuò)展: http://user:pass@host:port/path
。 user:pass
部分將以 base64 編碼為 HTTP 'Authorization' 標(biāo)頭,并在發(fā)起調(diào)用 XML-RPC 方法時(shí)作為連接過程的一部分發(fā)送給遠(yuǎn)程服務(wù)器。 你只需要在遠(yuǎn)程服務(wù)器要求基本身份驗(yàn)證賬號(hào)和密碼時(shí)使用此語(yǔ)法。 如果提供了 HTTPS URL,context 可以為 ssl.SSLContext
并配置有下層 HTTPS 連接的 SSL 設(shè)置。
返回的實(shí)例是一個(gè)代理對(duì)象,具有可被用來在遠(yuǎn)程服務(wù)器上發(fā)起相應(yīng) RPC 調(diào)用的方法。 如果遠(yuǎn)程服務(wù)器支持內(nèi)省 API,則也可使用該代理對(duì)象在遠(yuǎn)程服務(wù)器上查詢它所支持的方法(服務(wù)發(fā)現(xiàn))并獲取其他服務(wù)器相關(guān)的元數(shù)據(jù)
適用的類型(即可通過 XML 生成 marshall 對(duì)象),包括如下類型(除了已說明的例外,它們都會(huì)被反 marshall 為同樣的 Python 類型):
XML-RPC類型 |
Python 類型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
這是This is the full set of data types supported by XML-RPC 所支持?jǐn)?shù)據(jù)類型的完整集合。 方法調(diào)用也可能引發(fā)一個(gè)特殊的 Fault
實(shí)例,用來提示 XML-RPC 服務(wù)器錯(cuò)誤,或是用 ProtocolError
來提示 HTTP/HTTPS 傳輸層中的錯(cuò)誤。 Fault
和 ProtocolError
都派生自名為 Error
的基類。 請(qǐng)注意 xmlrpc client 模塊目前不可 marshal 內(nèi)置類型的子類的實(shí)例。
當(dāng)傳入字符串時(shí),XML 中的特殊字符如 <
, >
和 &
將被自動(dòng)轉(zhuǎn)義。 但是,調(diào)用方有責(zé)任確保字符串中沒有 XML 中不允許的字符,例如 ASCII 值在 0 和 31 之間的控制字符(當(dāng)然,制表、換行和回車除外);不這樣做將導(dǎo)致 XML-RPC 請(qǐng)求的 XML 格式不正確。 如果你必須通過 XML-RPC 傳入任意字節(jié)數(shù)據(jù),請(qǐng)使用 bytes
或 bytearray
類或者下文描述的 Binary
包裝器類。
Server
被保留作為 ServerProxy
的別名用于向下兼容。 新的代碼應(yīng)當(dāng)使用 ServerProxy
。
在 3.5 版更改: 增加了 context 參數(shù)。
在 3.6 版更改: 增加了對(duì)帶有前綴的類型標(biāo)簽的支持 (例如 ex:nil
)。 增加了對(duì)反 marshall 被 Apache XML-RPC 實(shí)現(xiàn)用于表示數(shù)值的附加類型的支持: i1
, i2
, i8
, biginteger
, float
和 bigdecimal
。 請(qǐng)參閱 http://ws.apache.org/xmlrpc/types.html 了解詳情。
參見
- XML-RPC HOWTO
以多種語(yǔ)言對(duì) XML-RPC 操作和客戶端軟件進(jìn)行了很好的說明。 包含 XML-RPC 客戶端開發(fā)者所需知道的幾乎任何事情。
- XML-RPC Introspection
描述了用于內(nèi)省的 XML-RPC 協(xié)議擴(kuò)展。
- XML-RPC Specification
官方規(guī)范說明。
ServerProxy 對(duì)象?
ServerProxy
實(shí)例有一個(gè)方法與 XML-RPC 服務(wù)器所接受的每個(gè)遠(yuǎn)程過程調(diào)用相對(duì)應(yīng)。 調(diào)用該方法會(huì)執(zhí)行一個(gè) RPC,通過名稱和參數(shù)簽名來調(diào)度(例如同一個(gè)方法名可通過多個(gè)參數(shù)簽名來重載)。 RPC 結(jié)束時(shí)返回一個(gè)值,它可以是適用類型的返回?cái)?shù)據(jù)或是表示錯(cuò)誤的 Fault
或 ProtocolError
對(duì)象。
支持 XML 內(nèi)省 API 的服務(wù)器還支持一些以保留的 system
屬性分組的通用方法:
- ServerProxy.system.listMethods()?
此方法返回一個(gè)字符串列表,每個(gè)字符串都各自對(duì)應(yīng) XML-RPC 服務(wù)器所支持的(非系統(tǒng))方法。
- ServerProxy.system.methodSignature(name)?
此方法接受一個(gè)形參,即某個(gè)由 XML-RPC 服務(wù)器所實(shí)現(xiàn)的方法名稱。 它返回一個(gè)由此方法可能的簽名組成的數(shù)組。 一個(gè)簽名就是一個(gè)類型數(shù)組。 這些類型中的第一個(gè)是方法的的返回類型,其余的均為形參。
由于允許多個(gè)簽名(即重載),此方法是返回一個(gè)簽名列表而非一個(gè)單例。
簽名本身被限制為一個(gè)方法所期望的最高層級(jí)形參。 舉例來說如果一個(gè)方法期望有一個(gè)結(jié)構(gòu)體數(shù)組作為形參,并返回一個(gè)字符串,則其簽名就是 "string, array"。 如果它期望有三個(gè)整數(shù)并返回一個(gè)字符串,則其簽名是 "string, int, int, int"。
如果方法沒有定義任何簽名,則將返回一個(gè)非數(shù)組值。 在 Python 中這意味著返回值的類型為列表以外的類型。
- ServerProxy.system.methodHelp(name)?
此方法接受一個(gè)形參,即 XML-RPC 服務(wù)器所實(shí)現(xiàn)的某個(gè)方法的名稱。 它返回描述相應(yīng)方法用法的文檔字符串。 如果沒有可用的文檔字符串,則返回空字符串。 文檔字符串可以包含 HTML 標(biāo)記。
在 3.5 版更改: ServerProxy
的實(shí)例支持 context manager 協(xié)議用于關(guān)閉下層傳輸。
以下是一個(gè)可運(yùn)行的示例。 服務(wù)器端代碼:
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()
前述服務(wù)器的客戶端代碼:
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 對(duì)象?
- class xmlrpc.client.DateTime?
該類的初始化可以使用距離 Unix 紀(jì)元的秒數(shù)、時(shí)間元組、ISO 8601 時(shí)間/日期字符串或
datetime.datetime
實(shí)例。 它具有下列方法,主要是為 marshall 和反 marshall 代碼的內(nèi)部使用提供支持:- decode(string)?
接受一個(gè)字符串作為實(shí)例的新時(shí)間值。
它還通過富比較和
__repr__()
方法來支持某些 Python 內(nèi)置運(yùn)算符。
以下是一個(gè)可運(yùn)行的示例。 服務(wù)器端代碼:
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()
前述服務(wù)器的客戶端代碼:
import xmlrpc.client
import datetime
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
today = proxy.today()
# convert the ISO8601 string to a datetime object
converted = datetime.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print("Today: %s" % converted.strftime("%d.%m.%Y, %H:%M"))
Binary 對(duì)象?
- class xmlrpc.client.Binary?
該類的初始化可以使用字節(jié)數(shù)據(jù)(可包括 NUL)。 對(duì)
Binary
對(duì)象的初始訪問是由一個(gè)屬性來提供的:Binary
對(duì)象具有下列方法,支持這些方法主要是供 marshall 和反 marshall 代碼在內(nèi)部使用:- encode(out)?
將此二進(jìn)制條目的 XML-RPC base 64 編碼格式寫入到 out 流對(duì)象。
被編碼數(shù)據(jù)將依據(jù) RFC 2045 第 6.8 節(jié) 每 76 個(gè)字符換行一次,這是撰寫 XML-RPC 規(guī)范說明時(shí) base64 規(guī)范的事實(shí)標(biāo)準(zhǔn)。
它還通過
__eq__()
和__ne__()
方法來支持某些 Python 內(nèi)置運(yùn)算符。
該二進(jìn)制對(duì)象的示例用法。 我們將通過 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()
客戶端會(huì)獲取圖片并將其保存為一個(gè)文件:
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 對(duì)象?
- class xmlrpc.client.Fault?
Fault
對(duì)象封裝了 XML-RPC fault 標(biāo)簽的內(nèi)容。 Fault 對(duì)象具有下列屬性:- faultCode?
一個(gè)指明 fault 類型的整數(shù)。
- faultString?
一個(gè)包含與 fault 相關(guān)聯(lián)的診斷消息的字符串。
在接下來的示例中我們將通過返回一個(gè)復(fù)數(shù)類型的值來故意引發(fā)一個(gè) Fault
。 服務(wù)器端代碼:
from xmlrpc.server import SimpleXMLRPCServer
# A marshalling error is going to occur because we're returning a
# complex number
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()
前述服務(wù)器的客戶端代碼:
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 對(duì)象?
- class xmlrpc.client.ProtocolError?
ProtocolError
對(duì)象描述了下層傳輸層中的協(xié)議錯(cuò)誤(例如當(dāng) URI 所指定的服務(wù)器不存在時(shí)的 404 'not found' 錯(cuò)誤)。 它具有下列屬性:- url?
觸發(fā)錯(cuò)誤的 URI 或 URL。
- errcode?
錯(cuò)誤代碼。
- errmsg?
錯(cuò)誤消息或診斷字符串。
- headers?
一個(gè)包含觸發(fā)錯(cuò)誤的 HTTP/HTTPS 請(qǐng)求的標(biāo)頭的字典。
在接下來的示例中我們將通過提供一個(gè)無(wú)效的 URI 來故意引發(fā)一個(gè) ProtocolError
:
import xmlrpc.client
# create a ServerProxy with a URI that doesn't respond to XMLRPC requests
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 對(duì)象?
MultiCall
對(duì)象提供了一種將對(duì)遠(yuǎn)程服務(wù)器的多個(gè)調(diào)用封裝為一個(gè)單獨(dú)請(qǐng)求的方式 1。
- class xmlrpc.client.MultiCall(server)?
創(chuàng)建一個(gè)用于盒式方法調(diào)用的對(duì)象。 server 是調(diào)用的最終目標(biāo)。 可以對(duì)結(jié)果對(duì)象發(fā)起調(diào)用,但它們將立即返回
None
,并只在MultiCall
對(duì)象中存儲(chǔ)調(diào)用名稱和形參。 調(diào)用該對(duì)象本身會(huì)導(dǎo)致所有已存儲(chǔ)的調(diào)用作為一個(gè)單獨(dú)的system.multicall
請(qǐng)求被發(fā)送。 此調(diào)用的結(jié)果是一個(gè) generator;迭代這個(gè)生成器會(huì)產(chǎn)生各個(gè)結(jié)果。
以下是該類的用法示例。 服務(wù)器端代碼:
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
# A simple server with simple arithmetic functions
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()
前述服務(wù)器的客戶端代碼:
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))
便捷函數(shù)?
- xmlrpc.client.dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)?
請(qǐng) params 轉(zhuǎn)換為一個(gè) XML-RPC 請(qǐng)求。 或者當(dāng) methodresponse 為真值時(shí)則轉(zhuǎn)換為一個(gè)請(qǐng)求。 params 可以是一個(gè)參數(shù)元組或是一個(gè)
Fault
異常類的實(shí)例。 如果 methodresponse 為真值,只有單獨(dú)的值可以被返回,這意味著 params 的長(zhǎng)度必須為 1。 如果提供了 encoding,則在生成的 XML 會(huì)使用該編碼格式;默認(rèn)的編碼格式為 UTF-8。 Python 的None
值不可在標(biāo)準(zhǔn) XML-RPC 中使用;要通過擴(kuò)展來允許使用它,請(qǐng)為 allow_none 提供一個(gè)真值。
- xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)?
將一個(gè) XML-RPC 請(qǐng)求或響應(yīng)轉(zhuǎn)換為 Python 對(duì)象
(params, methodname)
。 params 是一個(gè)參數(shù)元組;methodname 是一個(gè)字符串,或者如果數(shù)據(jù)包沒有提供方法名則為None
。 如果 XML-RPC 數(shù)據(jù)包是代表一個(gè)故障條件,則此函數(shù)將引發(fā)一個(gè)Fault
異常。 use_builtin_types 旗標(biāo)可被用于將日期/時(shí)間值表示為datetime.datetime
對(duì)象并將二進(jìn)制數(shù)據(jù)表示為bytes
對(duì)象;此旗標(biāo)默認(rèn)為假值。已過時(shí)的 use_datetime 旗標(biāo)與 use_builtin_types 類似但只作用于日期/時(shí)間值。
在 3.3 版更改: 增加了 use_builtin_types 旗標(biāo)。
客戶端用法的示例?
# simple test program (from the XML-RPC specification)
from xmlrpc.client import ServerProxy, Error
# server = ServerProxy("http://localhost:8000") # local server
with ServerProxy("http://betty.userland.com") as proxy:
print(proxy)
try:
print(proxy.examples.getStateName(41))
except Error as v:
print("ERROR", v)
要通過 HTTP 代理訪問一個(gè) XML-RPC 服務(wù)器,你必須自行定義一個(gè)傳輸。 下面的例子演示了具體做法:
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))
客戶端與服務(wù)器用法的示例?
備注
- 1
此做法被首次提及是在 a discussion on xmlrpc.com。