Содержание страницы
20.23. xmlrpclib – клиентский доступ XML-RPC¶xmlrpclib – XML-RPC client access
Примечание
Модуль xmlrpclib в Python 3 переименован в xmlrpc.client. Инструмент 2to3 при преобразовании исходного кода в Python 3 автоматически адаптирует импорты.
Новое в версии 2.2.
Исходный код: Lib/xmlrpclib.py
XML-RPC – это метод удалённого вызова процедур (Remote Procedure Call), использующий XML, передаваемый через HTTP(S) в качестве транспорта. С его помощью клиент может вызывать методы с параметрами на удалённом сервере (сервер задаётся URI) и получать структурированные данные. Этот модуль предназначен для написания кода XML-RPC клиента; он берёт на себя все детали преобразования между совместимыми объектами Python и XML, передаваемыми по сети.
Предупреждение
Модуль xmlrpclib не защищён от вредоносных данных.
Если требуется разбирать непроверенные или неаутентифицированные данные, см.
уязвимости XML.
Изменено в версии 2.7.9: Для URI HTTPS xmlrpclib теперь по умолчанию выполняет все необходимые проверки сертификата и имени хоста.
-
class
xmlrpclib.ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]])¶ Экземпляр
ServerProxy– это объект, управляющий связью с удалённым XML-RPC сервером. Обязательный первый аргумент – URI (Uniform Resource Indicator), обычно это URL сервера. Второй необязательный аргумент – экземпляр транспортной фабрики; по умолчанию для URL https: используется внутренний экземплярSafeTransport, а в остальных случаях – внутренний экземпляр HTTPTransport. Третий необязательный аргумент – кодировка, по умолчанию UTF-8. Четвёртый необязательный аргумент – флаг отладки.Следующие параметры управляют использованием возвращаемого экземпляра прокси. Если allow_none имеет значение true, то константа Python
Noneбудет преобразована в XML; по умолчаниюNoneвызывает исключениеTypeError. Это широко используемое расширение спецификации XML-RPC, но оно поддерживается не всеми клиентами и серверами; см. http://ontosys.com/xml-rpc/extensions.php. Флаг use_datetime можно использовать для представления значений даты/времени в виде объектовdatetime.datetime; по умолчанию это false. Объектыdatetime.datetimeмогут передаваться в вызовы.И HTTP, и HTTPS транспорты поддерживают расширение синтаксиса URL для HTTP-базовой аутентификации:
http://user:pass@host:port/path. Частьuser:passбудет закодирована в base64 как HTTP-заголовок 'Authorization' и отправлена на удалённый сервер в процессе подключения при вызове метода XML-RPC. Это нужно использовать только в том случае, если удалённый сервер требует имя пользователя и пароль для базовой аутентификации. Если указан HTTPS URL, context может бытьssl.SSLContextи настраивает параметры SSL нижележащего HTTPS-соединения.Возвращаемый экземпляр – это прокси-объект с методами, которые можно использовать для вызова соответствующих RPC-вызовов на удалённом сервере. Если удалённый сервер поддерживает API интроспекции, прокси также можно использовать для запроса методов, которые он поддерживает (обнаружение служб), и получения других метаданных, связанных с сервером.
Типы, которые являются совместимыми (т.е. могут быть преобразованы в XML), включают следующие (и, если не указано иное, они десериализуются как те же типы Python):
Тип XML-RPC
Тип Python
booleanintилиi4doublestringarraylistилиtuple, содержащие совместимые элементы. Массивы возвращаются какlists.structdict. Ключи должны быть строками, значения могут быть любого совместимого типа. Можно передавать объекты пользовательских классов; передаётся только их атрибут__dict__.dateTime.iso8601DateTimeилиdatetime.datetime. Возвращаемый тип зависит от значений флагов use_datetime.base64nilКонстанта
None. Передача разрешена только если allow_none равен true.Это полный набор типов данных, поддерживаемых XML-RPC. Вызовы методов также могут вызывать специальный экземпляр
Fault, используемый для сигнализации об ошибках сервера XML-RPC, илиProtocolError, используемый для сигнализации об ошибке на уровне транспорта HTTP/HTTPS. ОбаFaultиProtocolErrorпроисходят от базового классаError. Обратите внимание, что, хотя начиная с Python 2.2 можно создавать подклассы встроенных типов, модуль xmlrpclib в настоящее время не маршалирует экземпляры таких подклассов.При передаче строк символы, специальные для XML, такие как
<,>и&, будут автоматически экранированы. Однако вызывающая сторона должна убедиться, что строка не содержит символов, запрещённых в XML, например управляющих символов с ASCII-значениями от 0 до 31 (за исключением, конечно, табуляции, перевода строки и возврата каретки); несоблюдение этого приведёт к тому, что XML-RPC-запрос не будет корректным XML. Если необходимо передавать произвольные строки через XML-RPC, используйте класс-обёрткуBinary, описанный ниже.Serverсохранён как псевдоним дляServerProxyдля обратной совместимости. В новом коде следует использоватьServerProxy.Изменено в версии 2.5: Был добавлен флаг use_datetime.
Изменено в версии 2.6: Экземпляры классов нового стиля можно передавать, если они имеют __dict__ атрибут и не имеют базового класса, который маршалируется особым образом.
Изменено в версии 2.7.9: Добавлен аргумент context.
См. также
- Руководство по XML-RPC
Хорошее описание работы XML-RPC и клиентского ПО на нескольких языках. Содержит практически всё, что нужно знать разработчику XML-RPC клиента.
- Интроспекция XML-RPC
Описывает расширение протокола XML-RPC для интроспекции.
- Спецификация XML-RPC
Официальная спецификация.
- Неофициальные исправления XML-RPC
«Неофициальные исправления» Фредрика Лунда, предназначенные для разъяснения некоторых деталей спецификации XML-RPC, а также для указания на «лучшие практики» при разработке собственных реализаций XML-RPC.
20.23.1. Объекты ServerProxy¶ServerProxy Objects
Экземпляр 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 это означает, что тип возвращаемого значения будет чем-то отличным от list.
-
ServerProxy.system.methodHelp(name)¶ Этот метод принимает один параметр – имя метода, реализованного XML-RPC сервером. Он возвращает строку документации, описывающую использование этого метода. Если такая строка отсутствует, возвращается пустая строка. Строка документации может содержать HTML-разметку.
20.23.2. Логические объекты¶Boolean Objects
Этот класс может быть инициализирован любым значением Python; возвращаемый экземпляр зависит только от его истинностного значения. Он поддерживает различные операторы Python через методы __cmp__(), __repr__(), __int__() и __nonzero__(), реализованные очевидным образом.
Также он имеет следующий метод, предназначенный главным образом для внутреннего использования кодом демаршалинга:
-
Boolean.encode(out)¶ Записывает XML-RPC-кодирование этого логического элемента в объект потока out.
Далее следует работающий пример. Код сервера:
import xmlrpclib
from SimpleXMLRPCServer 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 xmlrpclib
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
print "3 is even: %s" % str(proxy.is_even(3))
print "100 is even: %s" % str(proxy.is_even(100))
20.23.3. Объекты DateTime¶DateTime Objects
-
class
xmlrpclib.DateTime¶ Этот класс можно инициализировать секундами с начала эпохи, временным кортежем, строкой даты/времени в формате ISO 8601 или экземпляром
datetime.datetime. Он имеет следующие методы, поддерживаемые в основном для внутреннего использования кодом маршалинга/демаршалинга:-
decode(string)¶ Принимает строку в качестве нового значения времени экземпляра.
Он также поддерживает некоторые встроенные операторы Python через
__cmp__()и__repr__().-
Далее следует работающий пример. Код сервера:
import datetime
from SimpleXMLRPCServer import SimpleXMLRPCServer
import xmlrpclib
def today():
today = datetime.datetime.today()
return xmlrpclib.DateTime(today)
server = SimpleXMLRPCServer(("localhost", 8000))
print "Listening on port 8000..."
server.register_function(today, "today")
server.serve_forever()
Клиентский код для указанного сервера:
import xmlrpclib
import datetime
proxy = xmlrpclib.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")
20.23.4. Объекты Binary¶Binary Objects
-
class
xmlrpclib.Binary¶ Этот класс может быть инициализирован строковыми данными (которые могут включать NUL). Основной доступ к содержимому объекта
Binaryпредоставляется через атрибут:-
data¶ Двоичные данные, инкапсулированные экземпляром
Binary. Данные предоставляются в виде 8-битной строки.
Объекты
Binaryимеют следующие методы, предназначенные в основном для внутреннего использования кодом маршалинга/демаршалинга:-
decode(string)¶ Принимает строку в base64 и декодирует её как новые данные экземпляра.
-
encode(out)¶ Записывает XML-RPC base64-кодировку этого двоичного объекта в потоковый объект out.
Закодированные данные будут содержать символы новой строки каждые 76 символов согласно RFC 2045, раздел 6.8, что было фактическим стандартом спецификации base64 на момент написания спецификации XML-RPC.
Он также поддерживает некоторые встроенные операторы Python через метод
__cmp__().-
Пример использования двоичных объектов. Мы собираемся передать изображение через XMLRPC:
from SimpleXMLRPCServer import SimpleXMLRPCServer
import xmlrpclib
def python_logo():
with open("python_logo.jpg", "rb") as handle:
return xmlrpclib.Binary(handle.read())
server = SimpleXMLRPCServer(("localhost", 8000))
print "Listening on port 8000..."
server.register_function(python_logo, 'python_logo')
server.serve_forever()
Клиент получает изображение и сохраняет его в файл:
import xmlrpclib
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
with open("fetched_python_logo.jpg", "wb") as handle:
handle.write(proxy.python_logo().data)
20.23.5. Объекты Fault¶Fault Objects
-
class
xmlrpclib.Fault¶ Объект
Faultинкапсулирует содержимое тега ошибки (fault tag) XML-RPC. Объекты Fault имеют следующие атрибуты:-
faultCode¶ Строка, указывающая тип ошибки.
-
faultString¶ Строка, содержащая диагностическое сообщение, связанное с ошибкой.
-
В следующем примере мы намеренно вызовем Fault, возвращая
объект сложного типа. Код сервера:
from SimpleXMLRPCServer 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 xmlrpclib
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
try:
proxy.add(2, 5)
except xmlrpclib.Fault as err:
print "A fault occurred"
print "Fault code: %d" % err.faultCode
print "Fault string: %s" % err.faultString
20.23.6. Объекты ProtocolError¶ProtocolError Objects
-
class
xmlrpclib.ProtocolError¶ Объект
ProtocolErrorописывает протокольную ошибку на уровне нижележащего транспорта (например, ошибку 404 «не найдено», если сервер по указанному URI не существует). Он имеет следующие атрибуты:-
url¶ URI или URL, вызвавший ошибку.
-
errcode¶ Код ошибки.
-
errmsg¶ Сообщение об ошибке или диагностическая строка.
-
headers¶ Строка, содержащая заголовки HTTP/HTTPS-запроса, вызвавшего ошибку.
-
В следующем примере мы намеренно вызовем ProtocolError, указав URI, не указывающий на сервер XMLRPC:
import xmlrpclib
# Создание ServerProxy с URI, который не отвечает на XMLRPC-запросы
proxy = xmlrpclib.ServerProxy("http://www.google.com/")
try:
proxy.some_method()
except xmlrpclib.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
20.23.7. Объекты MultiCall¶MultiCall Objects
Новое в версии 2.4.
Объект MultiCall позволяет инкапсулировать несколько вызовов к
удалённому серверу в один запрос 1.
-
class
xmlrpclib.MultiCall(server)¶ Создаёт объект для группировки вызовов методов. server – конечная цель вызова. Вызовы могут направляться результирующему объекту, но они сразу же возвращают
None, и сохраняют только имя метода и параметры в объектMultiCall. Вызов самого объекта приводит к передаче всех сохранённых вызовов в виде одного запросаsystem.multicall. Результатом этого вызова является generator; итерация по этому генератору даёт отдельные результаты.
Пример использования этого класса приведён ниже. Код сервера
from SimpleXMLRPCServer 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 xmlrpclib
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
multicall = xmlrpclib.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)
20.23.8. Вспомогательные функции¶Convenience Functions
-
xmlrpclib.boolean(value)¶ Преобразует любое значение Python в одну из логических констант XML-RPC:
TrueилиFalse.
-
xmlrpclib.dumps(params[, methodname[, methodresponse[, encoding[, allow_none]]]])¶ Преобразует params в запрос XML-RPC. Или в ответ, если methodresponse истинно. params может быть кортежем аргументов или экземпляром
Faultкласса исключения. Если methodresponse истинно, только одно значение может быть возвращено, то есть params должен иметь длину 1. encoding, если указан, это кодировка для генерируемого XML; по умолчанию UTF-8. ЗначениеNonePython не может использоваться в стандартном XML-RPC; чтобы разрешить его использование через расширение, передайте истинное значение для allow_none.
-
xmlrpclib.loads(data[, use_datetime])¶ Преобразует XML-RPC-запрос или ответ в объекты Python,
(params, methodname). params – кортеж аргументов; methodname – строка илиNone, если имя метода отсутствует в пакете. Если XML-RPC-пакет представляет условие ошибки, эта функция вызовет исключениеFault. Флаг use_datetime можно использовать, чтобы значения даты/времени представлялись как объектыdatetime.datetime; по умолчанию false.Изменено в версии 2.5: Был добавлен флаг use_datetime.
20.23.9. Пример использования клиента¶Example of Client Usage
# простая тестовая программа (из спецификации XML-RPC)
from xmlrpclib import ServerProxy, Error
# server = ServerProxy("http://localhost:8000") # локальный сервер
server = ServerProxy("http://betty.userland.com")
print server
try:
print server.examples.getStateName(41)
except Error as v:
print "ERROR", v
Для доступа к XML-RPC серверу через HTTP-прокси необходимо определить собственный транспорт. В следующем примере показано, как это сделать:
import xmlrpclib, httplib
class ProxiedTransport(xmlrpclib.Transport):
def set_proxy(self, proxy):
self.proxy = proxy
def make_connection(self, host):
self.realhost = host
h = httplib.HTTPConnection(self.proxy)
return h
def send_request(self, connection, handler, request_body):
connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler))
def send_host(self, connection, host):
connection.putheader('Host', self.realhost)
p = ProxiedTransport()
p.set_proxy('proxy-server:8080')
server = xmlrpclib.ServerProxy('http://time.xmlrpc.com/RPC2', transport=p)
print server.currentTime.getCurrentTime()
20.23.10. Пример использования клиента и сервера¶Example of Client and Server Usage
См. пример SimpleXMLRPCServer.
Сноски
- 1
Этот подход был впервые представлен в обсуждении на xmlrpc.com.