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. Вам нужно использовать это только в том случае, если удалённый сервер требует пользователя и пароль HTTP Basic Authentication. Если предоставлен URL 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. См. http://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) -
Записывает base64-кодирование этого бинарного элемента в объект потока 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 «not found», если сервер, указанный в 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. Значение 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 -
Этот подход был впервые представлен в обсуждении на xmlrpc.com.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/xmlrpc.client.html