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
現在預設執行所有必要的證書和主機名檢查。
可用性:非 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 為 true,Python 常量
None
將被轉換為 XML;預設行為是None
會引發TypeError
。這是 XML-RPC 規範中常用的一種擴充套件,但並非所有客戶端和伺服器都支援;有關描述,請參閱 http://ontosys.com/xml-rpc/extensions.php。use_builtin_types 標誌可用於使日期/時間值顯示為datetime.datetime
物件,二進位制資料顯示為bytes
物件;此標誌預設為 false。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 封送)的型別包括以下(除非另有說明,它們解封送後與 Python 型別相同):
XML-RPC 型別
Python 型別
boolean
int
、i1
、i2
、i4
、i8
或biginteger
範圍從 -2147483648 到 2147483647 的
int
。值獲得<int>
標籤。double
或float
float
。值獲得<double>
標籤。string
array
struct
dateTime.iso8601
DateTime
或datetime.datetime
。返回型別取決於 use_builtin_types 和 use_datetime 標誌的值。base64
nil
None
常量。僅當 allow_none 為 true 時才允許傳遞。bigdecimal
decimal.Decimal
。僅返回型別。這是 XML-RPC 支援的全部資料型別集。方法呼叫還可能引發特殊的
Fault
例項,用於指示 XML-RPC 伺服器錯誤,或ProtocolError
,用於指示 HTTP/HTTPS 傳輸層中的錯誤。無論是Fault
還是ProtocolError
都派生自一個名為Error
的基類。請注意,xmlrpc 客戶端模組目前不封送內建型別子類的例項。在傳遞字串時,XML 中的特殊字元(如
<
、>
和&
)將自動轉義。但是,呼叫者有責任確保字串不包含 XML 中不允許的字元,例如 ASCII 值在 0 到 31 之間的控制字元(當然,除了製表符、換行符和回車符);如果不這樣做,將導致 XML-RPC 請求不是格式良好的 XML。如果您必須透過 XML-RPC 傳遞任意位元組,請使用bytes
或bytearray
類或下面描述的Binary
包裝類。Server
作為ServerProxy
的別名被保留,以實現向後相容。新程式碼應該使用ServerProxy
。3.5 版本中有所改變: 添加了 context 引數。
3.6 版本中有所改變: 增加了對帶字首型別標籤(例如
ex:nil
)的支援。增加了對解析 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 內省
描述了用於內省的 XML-RPC 協議擴充套件。
- XML-RPC 規範
官方規範。
ServerProxy 物件¶
ServerProxy
例項具有與 XML-RPC 伺服器接受的每個遠端過程呼叫相對應的方法。呼叫該方法將執行 RPC,透過名稱和引數簽名進行分派(例如,相同的方法名稱可以過載多個引數簽名)。RPC 透過返回一個值完成,該值可以是相容型別中的返回資料,也可以是表示錯誤的 Fault
或 ProtocolError
物件。
支援 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
的例項支援 上下文管理器 協議以關閉底層傳輸。
以下是一個工作示例。伺服器程式碼:
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("https://: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¶
此類的初始化引數可以是自 epoch 以來的秒數、時間元組、ISO 8601 時間/日期字串,或
datetime.datetime
例項。它具有以下方法,主要供封送/解封送程式碼內部使用:- 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("https://: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 物件¶
- class xmlrpc.client.Binary¶
此類可以從位元組資料(可能包含空字元)初始化。訪問
Binary
物件內容的 主要方式 是透過一個屬性:Binary
物件具有以下方法,主要供封送/解封送程式碼內部使用:- encode(out)¶
將此二進位制項的 XML-RPC base64 編碼寫入 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("https://: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 物件具有以下屬性:- faultCode¶
表示錯誤型別的一個 int 值。
- faultString¶
一個字串,包含與錯誤相關的診斷訊息。
在下面的例子中,我們將透過返回一個複雜型別物件來故意引起一個 Fault
。伺服器程式碼:
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()
前述伺服器的客戶端程式碼:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("https://: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“未找到”錯誤)。它具有以下屬性:- url¶
觸發錯誤的 URI 或 URL。
- errcode¶
錯誤程式碼。
- errmsg¶
錯誤訊息或診斷字串。
- headers¶
一個字典,包含觸發錯誤的 HTTP/HTTPS 請求的頭部。
在下面的示例中,我們將透過提供無效的 URI 來故意引發 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 物件¶
MultiCall
物件提供了一種將對遠端伺服器的多個呼叫封裝到單個請求中的方式 [1]。
- class xmlrpc.client.MultiCall(server)¶
建立一個用於盒裝方法呼叫的物件。server 是最終的呼叫目標。可以對結果物件進行呼叫,但它們會立即返回
None
,並且只在MultiCall
物件中儲存呼叫名稱和引數。呼叫物件本身會導致所有儲存的呼叫作為單個system.multicall
請求傳輸。此呼叫的結果是一個 生成器;遍歷此生成器會產生各個結果。
以下是此類的使用示例。伺服器程式碼:
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()
前述伺服器的客戶端程式碼:
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("https://: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 為 true,則轉換為響應。params 可以是引數元組,也可以是
Fault
異常類的例項。如果 methodresponse 為 true,則只能返回單個值,這意味著 params 的長度必須為 1。encoding(如果提供)是生成 XML 中使用的編碼;預設為 UTF-8。Python 的None
值不能在標準 XML-RPC 中使用;要透過擴充套件允許使用它,請為 allow_none 提供 true 值。
- 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
物件的形式呈現;此標誌預設為 false。已棄用的 use_datetime 標誌與 use_builtin_types 相似,但它僅適用於日期/時間值。
3.3 版本中有所改變: 添加了 use_builtin_types 標誌。
客戶端用法示例¶
# simple test program (from the XML-RPC specification)
from xmlrpc.client import ServerProxy, Error
# server = ServerProxy("https://: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 代理訪問 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))
客戶端和伺服器用法示例¶
腳註