xmlrpc.client — Клиентский доступ к XML-RPC


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 (Uniform Resource Indicator) и обычно является URL-адресом сервера. Дополнительным вторым аргументом является сущность транспортной фабрики; по умолчанию это - внутренняя SafeTransport сущность для https: URL и внутренний HTTP Transport сущность иначе. Дополнительным третьим аргументом по умолчанию является кодировка 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. Это необходимо использовать только в том случае, если удаленному серверу требуются пользователь и пароль для обычной аутентификации. Если указан URL-адрес HTTPS, context можно ssl.SSLContext и настроить параметры SSL для базового подключения HTTPS.

Возвращенный сущность является прокси-объектом с методами, которые можно используемый для вызова соответствующих вызовов RPC на удаленном сервере. Если удаленный сервер поддерживает API интроспекции, прокси также может быть используемый для запроса на удаленном сервере методов, которые он поддерживает (обнаружение службы), и извлечения других связанных с сервером метаданных.

Типы, которые являются совместимыми (например, которые могут быть скомпонованы через XML), включают в себя следующие (и, за исключением отмеченных случаев, они не маркированы как тот же тип Python):

Тип XML-RPC Тип Python
boolean bool
int, i1, i2, i4, i8 или biginteger int в диапазоне от -2147483648 до 2147483647. Значения получают тег <int>.
double или float float. Значения получают тег <double>.
string str
array list или tuple, содержащие согласующиеся элементы. Массивы возвращенный как lists.
struct dict. Клавиши должны быть строки, значения могут быть любого типа. Объекты определяемых пользователем классов могут быть переданы; передается только их __dict__ атрибут.
dateTime.iso8601 DateTime или datetime.datetime. Возвращаемый тип зависит от значения флагов use_builtin_types и use_datetime.
base64 Binary, bytes или bytearray. Возвращаемый тип зависит от значения флага use_builtin_types.
nil Константа None. Передача разрешена только в том случае, если allow_none имеет значение true.
bigdecimal decimal.Decimal. Возвращается только тип.

Это полный набор типов данных, поддерживаемых XML-RPC. Вызов метода может также поднять специальную Fault сущность, используемую, чтобы сигнализировать, чтобы ошибки сервера XML-RPC или ProtocolError используемый сигнализировали об ошибке в транспортном уровне HTTP/HTTPS. И Fault, и ProtocolError являются производными от базового класса, называемого Error. Обратите внимание, что клиентский модуль xmlrpc в настоящее время не marshal сущности подклассы встроенных типов.

При передаче строки автоматически удаляются специальные символы XML, такие как <, > и &. Тем не менее, вызывающий должен убедиться, что строка не содержать символов, запрещенных в XML, таких как управляющие символы с значения ASCII от 0 до 31 (за исключением, конечно, табуляции, новой строки и каретки возвращает); если этого не сделать, запрос XML-RPC не будет правильно сформирован. Если требуется передать произвольные байты через 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
Описывает расширение протокола XML-RPC для внутреннего анализа.
Спецификация XML-RPC
Официальная спецификация.
Неофициальные ошибки XML-RPC
Фредрика Лундха (Fredrik Lundh’s) «Неофициальные ошибки, призванные прояснить некоторые детали в спецификации XML-RPC, а также намекнуть на» лучшие практики «для использования при разработке собственных реализаций XML-RPC».

Объекты ServerProxy

ServerProxy сущность имеет метод, соответствующий каждому удаленному вызову процедуры, принимаемому сервером XML-RPC. Вызов метода выполняет RPC, передаваемый по имени и сигнатуру аргументов (например, одно и то же имя метода может быть перегружено несколькими сигнатурами аргументов). RPC завершается возвращением значение, который может быть либо возвращенный данными соответствующего типа, либо объектом Fault или ProtocolError, указывающим на ошибку.

Серверы, поддерживающие API самоанализа XML, поддерживают некоторые общие методы, сгруппированные под зарезервированным system атрибут:

ServerProxy.system.listMethods()

Метод возвращает список строки, по одному для каждого (несистемного) метода, поддерживаемого сервером XML-RPC.

ServerProxy.system.methodSignature(name)

Метод принимает один параметр, имя метода, реализуемого сервером XML-RPC. Он возвращает массив возможных сигнатур для этого метода. Сигнатура - это массив типов. Первый из этих типов - возвращает тип метода, остальные - параметры.

Потому что несколько подписей (т.е. перегрузка), этот метод возвращает список подписей, а не одиночный.

Сами подписи ограничены параметрами верхнего уровня, ожидаемыми методом. Для сущность, если метод ожидает один массив структур в качестве параметра и он возвращает строка, его сигнатура просто «строка, массив». Если он ожидает три целых числа и возвращает строка, его сигнатура - «string, int, int, int».

Если для метода не определен сигнатура, значение возвращенный, не являющийся массивом. В 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()
# преобразовать ISO8601 строку в объект datetime
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

Класс может быть инициализирован из байтовых данных (которые могут включать в себя нулевые значения). Первичный доступ к содержимому объекта Binary обеспечивается атрибут:

data

Двоичные данные, инкапсулированные Binary сущность. Данные предоставляются как объект bytes.

Объекты Binary имеют следующие методы, поддерживаемые в основном для внутреннего использования маршаллинг/размаршаллинг код:

decode(bytes)

Принять объект base64 bytes и декодируйте его как новые данные сущности.

encode(out)

Записать 64 кодировка базы XML-RPC этого двоичного элемента в объект потока out.

Данные кодированный будут иметь новые строки каждые 76 символов согласно RFC 2045 секция 6.8, что было фактической стандартной спецификацией base64 при написании спецификации XML-RPC.

Он также поддерживает некоторые из Python’s встроенных операторов с помощью методов __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

# Произойдет ошибка маршаллинга, так как мы возвращаем комплексное число
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

# создайть ServerProxy с URI, который не отвечает на запросы XMLRPC
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)

Создать объект, используемый вызовам метода boxcar. 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

# Простой сервер с простыми арифметическими функциями
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. Python’s None значение не может быть используемый в стандартном XML-RPC; чтобы разрешить его использование через расширение, укажите истинный значение для 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.

Пример использования клиента

# простая тестовая программа (из спецификации XML-RPC)
from xmlrpc.client import ServerProxy, Error

# server = ServerProxy("http://localhost:8000") # локальный сервер
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.