xmlrpc.client
— Клиентский доступ XML-RPC¶
Исходный код: Lib/xmlrpc/client.py.
XML-RPC - это метод удаленного вызова процедур, который использует XML, передаваемый через HTTP(S) в качестве транспорта. С его помощью клиент может вызывать методы с параметрами на удаленном сервере (сервер именуется URI) и получать обратно структурированные данные. Этот модуль поддерживает написание клиентского кода XML-RPC; он обрабатывает все детали перевода между совместимыми объектами Python и XML на проводе.
Предупреждение
Модуль xmlrpc.client
не защищен от злонамеренно сконструированных данных. Если вам нужно разобрать недоверенные или неаутентифицированные данные, смотрите Уязвимости XML.
Изменено в версии 3.5: Для HTTPS URI xmlrpc.client
теперь по умолчанию выполняет все необходимые проверки сертификата и имени хоста.
-
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 (Uniform Resource Indicator), обычно это URL сервера. Необязательный второй аргумент - это экземпляр транспортной фабрики; по умолчанию это внутренний экземплярSafeTransport
для URL https: и внутренний экземпляр 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“)]). Устаревший флаг use_datetime аналогичен use_builtin_types, но применяется только к значениям даты/времени.
Изменено в версии 3.3: Был добавлен флаг use_builtin_types.
Изменено в версии 3.8: Был добавлен параметр headers.
Оба транспорта HTTP и HTTPS поддерживают расширение синтаксиса URL для базовой аутентификации HTTP: http://user:pass@host:port/path
. Часть user:pass
будет закодирована base64 в заголовке HTTP „Authorization“ и отправлена на удаленный сервер как часть процесса соединения при вызове метода XML-RPC. Это необходимо использовать только в том случае, если удаленный сервер требует пользователя и пароля базовой аутентификации. Если предоставляется HTTPS URL, context может быть ssl.SSLContext
и настраивает SSL параметры основного HTTPS соединения.
Возвращаемый экземпляр представляет собой объект прокси с методами, которые могут быть использованы для вызова соответствующих вызовов RPC на удаленном сервере. Если удаленный сервер поддерживает API интроспекции, прокси может также использоваться для запроса поддерживаемых им методов (обнаружение сервиса) и получения других связанных с сервером метаданных.
Типы, которые являются конформными (например, которые можно маршаллировать через XML), включают следующие типы (и, за исключением отмеченных случаев, они не маршаллируются как один и тот же тип Python):
Тип XML-RPC |
Тип Python |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Константа |
|
|
Это полный набор типов данных, поддерживаемых 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 Introspection
Описывает расширение протокола XML-RPC для интроспекции.
- XML-RPC Specification
Официальная спецификация.
Объекты ServerProxy¶
Экземпляр ServerProxy
имеет метод, соответствующий каждому удаленному вызову процедуры, принятому сервером XML-RPC. Вызов метода выполняет RPC, диспетчеризируемый как по имени, так и по сигнатуре аргументов (например, одно и то же имя метода может быть перегружено несколькими сигнатурами аргументов). RPC завершается возвратом значения, которое может быть либо возвращаемыми данными соответствующего типа, либо объектом Fault
или ProtocolError
, указывающим на ошибку.
Серверы, поддерживающие API интроспекции XML, поддерживают некоторые общие методы, сгруппированные под зарезервированным атрибутом 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
¶ Этот класс может быть инициализирован секундами от эпохи, кортежем времени, строкой времени/даты ISO 8601 или экземпляром
datetime.datetime
. Он имеет следующие методы, поддерживаемые в основном для внутреннего использования кодом маршалинга/размаршалинга:-
decode
(string)¶ Принимает строку в качестве нового значения времени экземпляра.
Он также поддерживает некоторые из встроенных операторов Python с помощью богатых методов сравнения и
__repr__()
.-
Ниже приведен рабочий пример. Код сервера:
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()
# 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"))
Бинарные объекты¶
-
class
xmlrpc.client.
Binary
¶ Этот класс может быть инициализирован из байтовых данных (которые могут включать NUL). Основной доступ к содержимому объекта
Binary
обеспечивается атрибутом:-
data
¶ Бинарные данные, инкапсулированные экземпляром
Binary
. Данные предоставляются в виде объектаbytes
.
Объекты
Binary
имеют следующие методы, поддерживаемые в основном для внутреннего использования кодом маршаллинга/немаршаллинга:-
encode
(out)¶ Запишите кодировку XML-RPC base 64 этого двоичного элемента в объект out stream.
Закодированные данные будут иметь новые строки через каждые 76 символов в соответствии с RFC 2045 section 6.8, который был де-факто стандартной спецификацией base64 на момент написания спецификации XML-RPC.
Он также поддерживает некоторые встроенные операторы Python с помощью методов
__eq__()
и__ne__()
.-
Пример использования бинарных объектов. Мы собираемся передать изображение через 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)
Объекты неисправностей¶
-
class
xmlrpc.client.
Fault
¶ Объект
Fault
инкапсулирует содержимое тега неисправности XML-RPC. Объекты неисправностей имеют следующие атрибуты:-
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("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
описывает ошибку протокола на нижележащем транспортном уровне (например, ошибка 404 «не найдено», если сервер, названный URI, не существует). Он имеет следующие атрибуты:-
url
¶ URI или URL, вызвавший ошибку.
-
errcode
¶ Код ошибки.
-
errmsg
¶ Сообщение об ошибке или диагностическая строка.
-
headers
¶ Диктат, содержащий заголовки HTTP/HTTPS запроса, который вызвал ошибку.
-
В следующем примере мы намеренно вызываем ошибку ProtocolError
, предоставляя неверный URI:
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
предоставляет способ инкапсуляции нескольких обращений к удаленному серверу в один запрос 1.
-
class
xmlrpc.client.
MultiCall
(server)¶ Создайте объект, используемый для вызова метода boxcar. Объект server является конечной целью вызова. Вызовы могут быть сделаны к объекту result, но они немедленно вернут
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
# 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("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 равен true. params может быть либо кортежем аргументов, либо экземпляром класса исключений
Fault
. Если methodresponse равен true, может быть возвращено только одно значение, то есть params должен иметь длину 1. encoding, если указано, это кодировка, которую следует использовать в генерируемом XML; по умолчанию это UTF-8. Значение PythonNone
не может использоваться в стандартном XML-RPC; чтобы разрешить его использование через расширение, укажите значение true для 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
; по умолчанию этот флаг равен 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("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)
Чтобы получить доступ к серверу XML-RPC через HTTP-прокси, необходимо определить пользовательский транспорт. В следующем примере показано, как это сделать:
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.
Сноски
- 1
Впервые этот подход был представлен в a discussion on xmlrpc.com.