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 例項,否則是內部的 HTTP Transport 例項。可選的第三個引數是編碼,預設是 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, bytesbytearray 物件可以傳遞給呼叫。headers 引數是可選的 HTTP 標頭序列,用於隨每個請求一起傳送,表示為表示標頭名稱和值的 2 元組序列。(例如,[('Header-Name', 'value')])。過時的 use_datetime 標誌類似於 use_builtin_types,但它僅適用於日期/時間值。

在 3.3 版本中更改: 添加了 use_builtin_types 標誌。

在 3.8 版本中更改: 添加了 headers 引數。

HTTP 和 HTTPS 傳輸都支援 HTTP 基本身份驗證的 URL 語法擴充套件:http://user:pass@host:port/pathuser:pass 部分將進行 base64 編碼為 HTTP “Authorization” 標頭,並在呼叫 XML-RPC 方法時作為連線過程的一部分發送到遠端伺服器。僅當遠端伺服器需要基本身份驗證使用者和密碼時才需要使用此功能。如果提供了 HTTPS URL,則 context 可以是 ssl.SSLContext 並配置底層 HTTPS 連線的 SSL 設定。

返回的例項是一個代理物件,其方法可用於呼叫遠端伺服器上的相應 RPC 呼叫。如果遠端伺服器支援自省 API,則代理還可以用於查詢遠端伺服器支援的方法(服務發現)並獲取其他伺服器關聯的元資料。

符合規範的型別(例如,可以透過 XML 編組的型別)包括以下型別(並且除非另有說明,否則它們將解組為相同的 Python 型別)

XML-RPC 型別

Python 型別

boolean

bool

int, i1, i2, i4, i8biginteger

在 -2147483648 到 2147483647 範圍內的 int。值獲取 <int> 標籤。

doublefloat

float。值獲取 <double> 標籤。

string

str

array

包含符合規範的元素的 listtuple。陣列作為 lists 返回。

struct

dict。鍵必須是字串,值可以是任何符合規範的型別。可以傳入使用者定義類的物件;僅傳輸其 __dict__ 屬性。

dateTime.iso8601

DateTimedatetime.datetime。返回的型別取決於 use_builtin_typesuse_datetime 標誌的值。

base64

Binary, bytesbytearray。返回的型別取決於 use_builtin_types 標誌的值。

nil

None 常量。僅當 allow_none 為 true 時才允許傳遞。

bigdecimal

decimal.Decimal。僅返回型別。

這是 XML-RPC 支援的完整資料型別集。方法呼叫也可能會引發特殊的 Fault 例項,用於表示 XML-RPC 伺服器錯誤,或 ProtocolError 用於表示 HTTP/HTTPS 傳輸層中的錯誤。FaultProtocolError 都派生自名為 Error 的基類。請注意,xmlrpc 客戶端模組目前不編組內建型別子類的例項。

當傳遞字串時,XML 特有的字元(例如 <>&)將自動轉義。但是,呼叫者有責任確保字串中不包含 XML 中不允許的字元,例如 ASCII 值在 0 到 31 之間的控制字元(當然,製表符、換行符和回車符除外);否則,將導致 XML-RPC 請求不是格式良好的 XML。如果必須透過 XML-RPC 傳遞任意位元組,請使用 bytesbytearray 類,或者使用下面描述的 Binary 包裝類。

Server 保留作為 ServerProxy 的別名,以便向後相容。新程式碼應使用 ServerProxy

在 3.5 版本中更改: 添加了 context 引數。

在 3.6 版本中更改: 添加了對帶有字首的型別標籤(例如 ex:nil)的支援。 添加了對 Apache XML-RPC 實現用於數字的其他型別進行解組的支援:i1i2i8bigintegerfloatbigdecimal。有關說明,請參閱 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 透過名稱和引數簽名分派(例如,可以使用多個引數簽名過載同一個方法名稱)。RPC 透過返回值來結束,該返回值可以是符合型別的返回資料,也可以是表示錯誤的 FaultProtocolError 物件。

支援 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

可以使用自紀元以來的秒數、時間元組、ISO 8601 時間/日期字串或 datetime.datetime 例項初始化此類。它具有以下方法,主要用於編組/解組程式碼的內部使用

decode(string)

接受字串作為例項的新時間值。

encode(out)

將此 DateTime 項的 XML-RPC 編碼寫入 out 流物件。

它還透過 rich comparison__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

可以使用位元組資料(可能包括 NUL)初始化此類。Binary 物件的內容的主要訪問方式是透過屬性

data

Binary 例項封裝的二進位制資料。資料以 bytes 物件的形式提供。

Binary 物件具有以下方法,主要用於編組/解組程式碼的內部使用

decode(bytes)

接受 base64 bytes 物件,並將其解碼為例項的新資料。

encode(out)

將此二進位制項的 XML-RPC base 64 編碼寫入 out 流物件。

根據 RFC 2045 第 6.8 節,編碼資料每 76 個字元將包含換行符,這是編寫 XML-RPC 規範時的事實上的標準 base64 規範。

它還透過 __eq__()__ne__() 方法支援某些 Python 的內建運算子。

二進位制物件的用法示例。我們將透過 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 標籤的內容。 Fault 物件具有以下屬性

faultCode

一個指示故障型別的整數。

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))

客戶端和伺服器用法示例

請參閱 SimpleXMLRPCServer 示例

腳註