xmlrpc.client --- XML-RPC 客戶(hù)端訪(fǎng)問(wèn)?

源代碼: Lib/xmlrpc/client.py


XML-RPC 是一種遠程過(guò)程調用方法,它以使用 HTTP(S) 傳遞的 XML 作為載體。 通過(guò)它,客戶(hù)端可以在遠程服務(wù)器(服務(wù)器以 URI 指明)上調用帶參數的方法并獲取結構化的數據。 本模塊支持編寫(xiě) XML-RPC 客戶(hù)端代碼;它會(huì )處理在通用 Python 對象和 XML 之間進(jìn)行在線(xiàn)翻譯的所有細節。

警告

xmlrpc.client 模塊對于惡意構建的數據是不安全的。 如果你需要解析不受信任或未經(jīng)身份驗證的數據,請參閱 XML 漏洞。

在 3.5 版更改: 對于 HTTPS URI,現在 xmlrpc.client 默認會(huì )執行所有必要的證書(shū)和主機名檢查。

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í)例是管理與遠程 XML-RPC 服務(wù)器通信的對象。 要求的第一個(gè)參數為 URI (統一資源定位符),通常就是服務(wù)器的 URL。 可選的第二個(gè)參數為傳輸工廠(chǎng)實(shí)例;在默認情況下對于 https: URL 是一個(gè)內部 SafeTransport 實(shí)例,在其他情況下則是一個(gè)內部 HTTP Transport 實(shí)例。 可選的第三個(gè)參數為編碼格式,默認為 UTF-8。 可選的第四個(gè)參數為調試旗標。

下列形參控制所返回代理實(shí)例的使用。 如果 allow_none 為真值,則 Python 常量 None 將被轉寫(xiě)為 XML;默認行為是針對 None 引發(fā) TypeError。 這是對 XML-RPC 規格的一個(gè)常用擴展,但并不被所有客戶(hù)端和服務(wù)器所支持;請參閱 http://ontosys.com/xml-rpc/extensions.php 了解詳情。 use_builtin_types 旗標可被用來(lái)將日期/時(shí)間值表示為 datetime.datetime 對象而將二進(jìn)制數據表示為 bytes 對象;此旗標默認為假值。 datetime.datetime, bytesbytearray 對象可以被傳給調用操作。 headers 形參為可選的隨每次請求發(fā)送的 HTTP 標頭序列,其形式為包含代表標頭名稱(chēng)和值的 2 元組的序列 (例如 [('Header-Name', 'value')])。 已不再適用的 use_datetime 旗標與 use_builtin_types 類(lèi)似但它只針對日期/時(shí)間值。

在 3.3 版更改: 增加了 use_builtin_types 旗標。

在 3.8 版更改: 增加了 headers 形參。

HTTP 和 HTTPS 傳輸均支持用于 HTTP 基本身份驗證的 URL 語(yǔ)法擴展: http://user:pass@host:port/path。 user:pass 部分將以 base64 編碼為 HTTP 'Authorization' 標頭,并在發(fā)起調用 XML-RPC 方法時(shí)作為連接過(guò)程的一部分發(fā)送給遠程服務(wù)器。 你只需要在遠程服務(wù)器要求基本身份驗證賬號和密碼時(shí)使用此語(yǔ)法。 如果提供了 HTTPS URL,context 可以為 ssl.SSLContext 并配置有下層 HTTPS 連接的 SSL 設置。

返回的實(shí)例是一個(gè)代理對象,具有可被用來(lái)在遠程服務(wù)器上發(fā)起相應 RPC 調用的方法。 如果遠程服務(wù)器支持內省 API,則也可使用該代理對象在遠程服務(wù)器上查詢(xún)它所支持的方法(服務(wù)發(fā)現)并獲取其他服務(wù)器相關(guān)的元數據

適用的類(lèi)型(即可通過(guò) XML 生成 marshall 對象),包括如下類(lèi)型(除了已說(shuō)明的例外,它們都會(huì )被反 marshall 為同樣的 Python 類(lèi)型):

XML-RPC類(lèi)型

Python 類(lèi)型

boolean

bool

int, i1, i2, i4, i8 或者 biginteger

int 的范圍從 -2147483648 到 2147483647。值將獲得 <int> 標志。

doublefloat

float。值將獲得 <double> 標志。

string

str

array

listtuple 包含整合元素。數組以 lists 形式返回。

struct

dict。 鍵必須為字符串,值可以為任何適用的類(lèi)型。 可以傳入用戶(hù)自定義類(lèi)的對象;只有其 __dict__ 屬性會(huì )被傳輸。

dateTime.iso8601

DateTimedatetime.datetime。返回的類(lèi)型取決于 use_builtin_typesuse_datetime 標志的值。

base64

Binary, bytesbytearray。返回的類(lèi)型取決于 use_builtin_types 標志的值。

nil

None 常量。僅當 allow_none 為true時(shí)才允許傳遞。

bigdecimal

decimal.Decimal. 僅返回類(lèi)型。

這是This is the full set of data types supported by XML-RPC 所支持數據類(lèi)型的完整集合。 方法調用也可能引發(fā)一個(gè)特殊的 Fault 實(shí)例,用來(lái)提示 XML-RPC 服務(wù)器錯誤,或是用 ProtocolError 來(lái)提示 HTTP/HTTPS 傳輸層中的錯誤。 FaultProtocolError 都派生自名為 Error 的基類(lèi)。 請注意 xmlrpc client 模塊目前不可 marshal 內置類(lèi)型的子類(lèi)的實(shí)例。

當傳入字符串時(shí),XML 中的特殊字符如 <, >& 將被自動(dòng)轉義。 但是,調用方有責任確保字符串中沒(méi)有 XML 中不允許的字符,例如 ASCII 值在 0 和 31 之間的控制字符(當然,制表、換行和回車(chē)除外);不這樣做將導致 XML-RPC 請求的 XML 格式不正確。 如果你必須通過(guò) XML-RPC 傳入任意字節數據,請使用 bytesbytearray 類(lèi)或者下文描述的 Binary 包裝器類(lèi)。

Server 被保留作為 ServerProxy 的別名用于向下兼容。 新的代碼應當使用 ServerProxy。

在 3.5 版更改: 增加了 context 參數。

在 3.6 版更改: 增加了對帶有前綴的類(lèi)型標簽的支持 (例如 ex:nil)。 增加了對反 marshall 被 Apache XML-RPC 實(shí)現用于表示數值的附加類(lèi)型的支持: i1, i2, i8, biginteger, floatbigdecimal。 請參閱 http://ws.apache.org/xmlrpc/types.html 了解詳情。

參見(jiàn)

XML-RPC HOWTO

以多種語(yǔ)言對 XML-RPC 操作和客戶(hù)端軟件進(jìn)行了很好的說(shuō)明。 包含 XML-RPC 客戶(hù)端開(kāi)發(fā)者所需知道的幾乎任何事情。

XML-RPC Introspection

描述了用于內省的 XML-RPC 協(xié)議擴展。

XML-RPC Specification

官方規范說(shuō)明。

ServerProxy 對象?

ServerProxy 實(shí)例有一個(gè)方法與 XML-RPC 服務(wù)器所接受的每個(gè)遠程過(guò)程調用相對應。 調用該方法會(huì )執行一個(gè) RPC,通過(guò)名稱(chēng)和參數簽名來(lái)調度(例如同一個(gè)方法名可通過(guò)多個(gè)參數簽名來(lái)重載)。 RPC 結束時(shí)返回一個(gè)值,它可以是適用類(lèi)型的返回數據或是表示錯誤的 FaultProtocolError 對象。

支持 XML 內省 API 的服務(wù)器還支持一些以保留的 system 屬性分組的通用方法:

ServerProxy.system.listMethods()?

此方法返回一個(gè)字符串列表,每個(gè)字符串都各自對應 XML-RPC 服務(wù)器所支持的(非系統)方法。

ServerProxy.system.methodSignature(name)?

此方法接受一個(gè)形參,即某個(gè)由 XML-RPC 服務(wù)器所實(shí)現的方法名稱(chēng)。 它返回一個(gè)由此方法可能的簽名組成的數組。 一個(gè)簽名就是一個(gè)類(lèi)型數組。 這些類(lèi)型中的第一個(gè)是方法的的返回類(lèi)型,其余的均為形參。

由于允許多個(gè)簽名(即重載),此方法是返回一個(gè)簽名列表而非一個(gè)單例。

簽名本身被限制為一個(gè)方法所期望的最高層級形參。 舉例來(lái)說(shuō)如果一個(gè)方法期望有一個(gè)結構體數組作為形參,并返回一個(gè)字符串,則其簽名就是 "string, array"。 如果它期望有三個(gè)整數并返回一個(gè)字符串,則其簽名是 "string, int, int, int"。

如果方法沒(méi)有定義任何簽名,則將返回一個(gè)非數組值。 在 Python 中這意味著(zhù)返回值的類(lèi)型為列表以外的類(lèi)型。

ServerProxy.system.methodHelp(name)?

此方法接受一個(gè)形參,即 XML-RPC 服務(wù)器所實(shí)現的某個(gè)方法的名稱(chēng)。 它返回描述相應方法用法的文檔字符串。 如果沒(méi)有可用的文檔字符串,則返回空字符串。 文檔字符串可以包含 HTML 標記。

在 3.5 版更改: ServerProxy 的實(shí)例支持 context manager 協(xié)議用于關(guān)閉下層傳輸。

以下是一個(gè)可運行的示例。 服務(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ù)器的客戶(hù)端代碼:

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?

該類(lèi)的初始化可以使用距離 Unix 紀元的秒數、時(shí)間元組、ISO 8601 時(shí)間/日期字符串或 datetime.datetime 實(shí)例。 它具有下列方法,主要是為 marshall 和反 marshall 代碼的內部使用提供支持:

decode(string)?

接受一個(gè)字符串作為實(shí)例的新時(shí)間值。

encode(out)?

將此 DateTime 條目的 XML-RPC 編碼格式寫(xiě)入到 out 流對象。

它還通過(guò)富比較和 __repr__() 方法來(lái)支持某些 Python 內置運算符。

以下是一個(gè)可運行的示例。 服務(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ù)器的客戶(hù)端代碼:

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 對象?

class xmlrpc.client.Binary?

該類(lèi)的初始化可以使用字節數據(可包括 NUL)。 對 Binary 對象的初始訪(fǎng)問(wèn)是由一個(gè)屬性來(lái)提供的:

data?

Binary 實(shí)例封裝的二進(jìn)制數據。 該數據以 bytes 對象的形式提供。

Binary 對象具有下列方法,支持這些方法主要是供 marshall 和反 marshall 代碼在內部使用:

decode(bytes)?

接受一個(gè) base64 bytes 對象并將其解碼為實(shí)例的新數據。

encode(out)?

將此二進(jìn)制條目的 XML-RPC base 64 編碼格式寫(xiě)入到 out 流對象。

被編碼數據將依據 RFC 2045 第 6.8 節 每 76 個(gè)字符換行一次,這是撰寫(xiě) XML-RPC 規范說(shuō)明時(shí) base64 規范的事實(shí)標準。

它還通過(guò) __eq__()__ne__() 方法來(lái)支持某些 Python 內置運算符。

該二進(jìn)制對象的示例用法。 我們將通過(guò) XMLRPC 來(lái)傳輸一張圖片:

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

客戶(hù)端會(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 對象?

class xmlrpc.client.Fault?

Fault 對象封裝了 XML-RPC fault 標簽的內容。 Fault 對象具有下列屬性:

faultCode?

一個(gè)指明 fault 類(lèi)型的整數。

faultString?

一個(gè)包含與 fault 相關(guān)聯(lián)的診斷消息的字符串。

在接下來(lái)的示例中我們將通過(guò)返回一個(gè)復數類(lèi)型的值來(lái)故意引發(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ù)器的客戶(hù)端代碼:

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 對象描述了下層傳輸層中的協(xié)議錯誤(例如當 URI 所指定的服務(wù)器不存在時(shí)的 404 'not found' 錯誤)。 它具有下列屬性:

url?

觸發(fā)錯誤的 URI 或 URL。

errcode?

錯誤代碼。

errmsg?

錯誤消息或診斷字符串。

headers?

一個(gè)包含觸發(fā)錯誤的 HTTP/HTTPS 請求的標頭的字典。

在接下來(lái)的示例中我們將通過(guò)提供一個(gè)無(wú)效的 URI 來(lái)故意引發(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 對象?

MultiCall 對象提供了一種將對遠程服務(wù)器的多個(gè)調用封裝為一個(gè)單獨請求的方式 1。

class xmlrpc.client.MultiCall(server)?

創(chuàng )建一個(gè)用于盒式方法調用的對象。 server 是調用的最終目標。 可以對結果對象發(fā)起調用,但它們將立即返回 None,并只在 MultiCall 對象中存儲調用名稱(chēng)和形參。 調用該對象本身會(huì )導致所有已存儲的調用作為一個(gè)單獨的 system.multicall 請求被發(fā)送。 此調用的結果是一個(gè) generator;迭代這個(gè)生成器會(huì )產(chǎn)生各個(gè)結果。

以下是該類(lèi)的用法示例。 服務(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ù)器的客戶(hù)端代碼:

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 轉換為一個(gè) XML-RPC 請求。 或者當 methodresponse 為真值時(shí)則轉換為一個(gè)請求。 params 可以是一個(gè)參數元組或是一個(gè) Fault 異常類(lèi)的實(shí)例。 如果 methodresponse 為真值,只有單獨的值可以被返回,這意味著(zhù) params 的長(cháng)度必須為 1。 如果提供了 encoding,則在生成的 XML 會(huì )使用該編碼格式;默認的編碼格式為 UTF-8。 Python 的 None 值不可在標準 XML-RPC 中使用;要通過(guò)擴展來(lái)允許使用它,請為 allow_none 提供一個(gè)真值。

xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)?

將一個(gè) XML-RPC 請求或響應轉換為 Python 對象 (params, methodname)。 params 是一個(gè)參數元組;methodname 是一個(gè)字符串,或者如果數據包沒(méi)有提供方法名則為 None。 如果 XML-RPC 數據包是代表一個(gè)故障條件,則此函數將引發(fā)一個(gè) Fault 異常。 use_builtin_types 旗標可被用于將日期/時(shí)間值表示為 datetime.datetime 對象并將二進(jìn)制數據表示為 bytes 對象;此旗標默認為假值。

已過(guò)時(shí)的 use_datetime 旗標與 use_builtin_types 類(lèi)似但只作用于日期/時(shí)間值。

在 3.3 版更改: 增加了 use_builtin_types 旗標。

客戶(hù)端用法的示例?

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

要通過(guò) HTTP 代理訪(fǎng)問(wèn)一個(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))

客戶(hù)端與服務(wù)器用法的示例?

參見(jiàn) SimpleXMLRPCServer 示例。

備注

1

此做法被首次提及是在 a discussion on xmlrpc.com。