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

Исходный код: Lib/xmlrpc/client.py


XML-RPC - это метод удаленного вызова процедур, который использует XML, передаваемый по протоколу HTTP(S) в качестве транспортного средства. С его помощью клиент может вызывать методы с параметрами на удаленном сервере (сервер именуется URI) и получать обратно структурированные данные. Этот модуль поддерживает написание клиентского кода на основе XML-RPC; он обрабатывает все детали перевода между совместимыми объектами Python и XML по проводам.

Предупреждение

Модуль xmlrpc.client не защищен от вредоносных данных. Если вам нужно проанализировать данные, которым нельзя доверять или которые не прошли проверку подлинности, обратитесь к Важно отметить, что для модулей в пакете требуется, чтобы был доступен хотя бы один синтаксический анализатор XML, совместимый с SAX. Синтаксический анализатор Expat включен в состав Python, поэтому модуль всегда будет доступен..

Изменено в версии 3.5: Для URI HTTPS xmlrpc.client теперь по умолчанию выполняются все необходимые проверки сертификата и имени хоста.

Availability: это не Emscripten, это был не я.

Этот модуль не работает или недоступен на платформах WebAssembly wasm32-emscripten и wasm32-wasi. Дополнительную информацию смотрите в разделе Платформы веб-сборки.

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 и внутренний экземпляр HTTP Transport в противном случае. Необязательный третий аргумент - это кодировка, по умолчанию UTF-8. Необязательный четвертый аргумент - это флаг отладки.

Следующие параметры определяют использование возвращаемого экземпляра прокси-сервера. Если значение allow_none равно true, константа Python None будет преобразована в XML; по умолчанию None вызывает TypeError. Это широко используемое расширение спецификации XML-RPC, но оно поддерживается не всеми клиентами и серверами; описание приведено в разделе http://ontosys.com/xml-rpc/extensions.php. Флаг use_buildin_types может использоваться для отображения значений даты/времени в виде datetime.datetime объектов, а двоичных данных - в виде bytes объектов; по умолчанию этот флаг имеет значение false. datetime.datetime, <<<Объекты bytes 7>>> и bytearray могут передаваться в вызовы. Параметр headers - это необязательная последовательность HTTP-заголовков для отправки с каждым запросом, выраженная в виде последовательности из 2 кортежей, представляющих имя и значение заголовка. (например, [('Header-Name', 'value')]). Устаревший флаг use_datetime аналогичен флагу use_buildin_types, но он применяется только к значениям даты и времени.

Изменено в версии 3.3: Был добавлен флаг use_buildin_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_buildin_types и use_datetime.

base64

Binary, bytes или bytearray. Возвращаемый тип зависит от значения флага use_buildin_types.

nil

Константа None. Передача разрешена, только если значение allow_none равно true.

bigdecimal

decimal.Decimal. Возвращаемый только тип.

Это полный набор типов данных, поддерживаемых 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 имеет метод, соответствующий каждому удаленному вызову процедуры, принимаемому сервером XML-RPC. При вызове метода выполняется RPC, отправляемый как по имени, так и по сигнатуре аргумента (например, одно и то же имя метода может быть перегружено несколькими сигнатурами аргументов). RPC завершает работу, возвращая значение, которое может быть либо возвращаемыми данными соответствующего типа, либо объектом Fault или ProtocolError, указывающим на ошибку.

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

ServerProxy.system.listMethods()

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

ServerProxy.system.methodSignature(name)

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

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

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

Если для метода не определена сигнатура, возвращается значение, не являющееся массивом. В Python это означает, что тип возвращаемого значения будет иным, чем list.

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)))

Объекты даты и времени

class xmlrpc.client.DateTime

Этот класс может быть инициализирован секундами с момента начала эпохи, временным кортежем, строкой времени/даты ISO 8601 или экземпляром datetime.datetime. В нем есть следующие методы, поддерживаемые в основном для внутреннего использования кодом сортировки/отмены сортировки:

decode(string)

Примите строку в качестве нового значения времени экземпляра.

encode(out)

Запишите кодировку XML-RPC этого элемента DateTime в объект out stream.

Он также поддерживает некоторые встроенные операторы 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 объекты имеют следующие методы, поддерживаемые в основном для внутреннего использования кодом сортировки/отмены сортировки:

decode(bytes)

Примите объект base64 bytes и расшифруйте его как новые данные экземпляра.

encode(out)

Запишите кодировку XML-RPC base64 для этого двоичного элемента в объект 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)

Объекты ошибок протокола

class xmlrpc.client.ProtocolError

Объект ProtocolError описывает ошибку протокола на базовом транспортном уровне (например, ошибку 404 «не найден», если сервер, указанный в URI, не существует). Он имеет следующие атрибуты:

url

URI или URL-адрес, который вызвал ошибку.

errcode

Код ошибки.

errmsg

Сообщение об ошибке или диагностическая строка.

headers

Dict, содержащий заголовки запроса 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. сервер является конечной целью вызова. Вызовы могут быть выполнены к результирующему объекту, но они немедленно вернут 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. Значение Python 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_buildin_types может использоваться для отображения значений даты/времени в виде datetime.datetime объектов, а двоичных данных - в виде bytes объектов; по умолчанию этот флаг имеет значение false.

Устаревший флаг use_datetime аналогичен флагу use_buildin_types, но он применяется только к значениям даты и времени.

Изменено в версии 3.3: Был добавлен флаг use_buildin_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.

Сноски

Вернуться на верх