xmlrpc.client — Доступ к клиенту XML-RPC
Исходный код: Lib/xmlrpc/client.py
XML-RPC — это метод удаленного вызова процедур, который использует XML, передаваемый по протоколу HTTP(S), в качестве транспорта. С помощью него клиент может вызывать методы с параметрами на удалённом сервере (сервер указывается URI) и получать обратно структурированные данные. Этот модуль поддерживает написание кода клиентов XML-RPC; он обрабатывает все детали преобразования между совместимыми объектами Python и XML в сети.
Предупреждение
Модуль xmlrpc.client не является безопасным при работе с вредоносными данными. Если вам нужно обработать недоверенные или неавторизованные данные, см. Уязвимости XML.
Изменено в версии 3.5: Для URI HTTPS 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 (указатель ресурса), который обычно представляет собой URL сервера. Необязательный второй аргумент — экземпляр фабрики транспорта; по умолчанию это внутренний экземплярSafeTransportдля HTTPS-URL и внутренний экземпляр 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 Basic Authentication: http://user:pass@host:port/path. Часть user:pass будет закодирована в base64 в качестве HTTP-заголовка ‘Authorization’ и отправлена на удалённый сервер в процессе подключения при вызове метода XML-RPC. Вам нужно использовать этот параметр только в том случае, если удалённый сервер требует имени пользователя и пароля Basic Authentication. Если предоставлен 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 сервером. Он возвращает массив возможных сигнатур для этого метода. Сигнатура — это массив типов. Первый из этих типов — тип возвращаемого значения метода, остальные — параметры.
Поскольку разрешается несколько сигнатур (т. е. перегрузка), этот метод возвращает список сигнатур, а не одиночный элемент.
Сами сигнатуры ограничены верхним уровнем параметров, ожидаемых методом. Например, если метод ожидает один массив структур в качестве параметра и возвращает строку, его сигнатура — просто «строка, массив». Если он ожидает три целых числа и возвращает строку, его сигнатура — «строка, целое, целое, целое».
Если для метода не определена сигнатура, возвращается значение, не являющееся массивом. В 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("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) -
Принимает строку в качестве нового значения времени экземпляра.
-
encode(out) -
Записывает XML-RPC кодировку этого элемента
DateTimeв объект потока out.
Он также поддерживает некоторые встроенные операторы 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 -
Этот класс может быть инициализирован данными типа bytes (которые могут включать NUL). Основной доступ к содержимому объекта
Binaryпредоставляется атрибутом:-
data -
Бинарные данные, инкапсулированные экземпляром
Binary. Данные предоставляются как объектbytes.
Объекты
Binaryимеют следующие методы, поддерживаемые в основном для внутреннего использования кодом сериализации/десериализации:-
decode(bytes) -
Принимает объект base64
bytesи декодирует его как новые данные экземпляра.
-
encode(out) -
Записывает XML-RPC кодировку в base 64 этого бинарного элемента в объект потока out.
Закодированные данные будут иметь новые строки через каждые 76 символов, согласно RFC 2045 раздел 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)
Объекты Fault
-
class xmlrpc.client.Fault -
Объект
Faultинкапсулирует содержимое тега ошибки XML-RPC. Объекты 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("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
Объект 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("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языка Python не может использоваться в стандартном 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 -
Этот подход был впервые представлен в обсуждении на xmlrpc.com.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/xmlrpc.client.html