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
теперь по умолчанию выполняет все необходимые проверки сертификата и имени хоста.
Availability: не 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 (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-адрес, 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 с помощью методов
rich comparison
и__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¶
Число 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("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. Питоновское значениеNone
не может использоваться в стандартном 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.
Сноски