Building a Web Services in Python
Поднимаем XML веб-сервис на Пайтоне
1. Python:
В системе должен быть установлен python, версии не ниже 2.3
2. Устанавливаем apache ( httpd-2.2.8 ):
$ ./configure --prefix=/usr/local/apache2-soap \ --with-mpm=prefork \ --enable-so \ --enable-mods-shared="actions alias asis auth rewrite ssl" \ --disable-userdir \ --disable-cgi \ --disable-include \ --disable-autoindex $ make $ make installЗдесь, в общем-то, обычная установка apache. И если у вас уже есть apache, можно использовать его. Здесь я попытался собрать «лёгкий» апач, с минимумом модулей. Использовать можно как apache 1.3, так и apache 2.0 или 2.2
3. Устанавливаем mod_python ( mod_python-3.3.1 )
$ ./configure \ --with-apxs=/usr/local/apache2-soap/bin/apxs \ --without-flex $ make $ make install
Обратите внимание, что mod_python 3.3.1 только для apache версии 2.0 и 2.2. Если у вас apache 1.3, используйте mod_python 2.7.11
4. Устанавливаем ZSI ( The Zolera Soap Infrastructure ):
Берём ZSI не ниже версии ZSI-2.1-a1, ZSI-2.0 имеет баги. Установка либо традиционным для python образом:
$ python ./setup.py install
Или можно использовать уже собранный пакет ZSI для python нужной версии, например так:
$ easy_install http://heanet.dl.sourceforge.net/sourceforge/pywebsvcs/ZSI-2.1_a1-py2.4.egg
5. Конфигурируем Apache:
Конфигурируем Apache и виртуальный хост по вкусу.
Если предположить, что скрипты для обработки запросов будут расположены тут: /usr/local/apache2-soap/soapagent, то добавляем Location для обработки веб-сервиса:
<Location /soapagent> SetHandler mod_python PythonPath "['/usr/local/apache2-soap/soapagent']+sys.path" PythonHandler soapagent_handler # PythonAutoReload On # PythonDebug On </Location>
Oпиции PythonAutoReload On и PythonDebug On удобно использовать при отладке, но для продакшин использования лучше выключить.
Если у вас apache 1.3 с mod_python 2.7.11, то конфигурация Location будет немного иной:
<Location /soapagent> SetHandler python-program PythonPath "['/usr/local/apache2-soap/soapagent']+sys.path" PythonHandler soapagent_handler # PythonAutoReload On # PythonDebug On </Location>
6. Конвертируем WSDL в python методы:
При установке ZSI в системе должен появиться скрипт, который умеет конвертировать WSDL файлы в python методы. Это делается так:
$ wsdl2py http://kocmuk.ru/files/2008/05/soapagent.wsdl
Конвертация возможна как с удалённого wsdl, так и с локального:
$ wget http://kocmuk.ru/files/2008/05/soapagent.wsdl $ wsdl2py ./soapagent.wsdl
В результате получаем три файла: soapagent_client.py, soapagent_server.py, soapagent_types.py. На основе soapagent_client.py можно сделать клиента, но для сервера достаточно soapagent_server.py, soapagent_types.py. Эти два скрипта нужно положить туда же, где, как мы договорились, будут расположены скрипты для обработки запросов, т.е. в /usr/local/apache2-soap/soapagent
Для данного примера WSDL файл можно взять тут:http://kocmuk.ru/files/2008/05/soapagent.wsdl
Обратите внимание, что URL, на котором будет жить веб-сервис указан внутри wsdl. В данном случает он такой: location="http://localhost:8080/soapagent". Потому веб-сервис надо поднимать именно на этом URL или изменить location в wsdl на требуемый. А так же, хорошо бы сам WSDL выложить в общий доступ, что бы клиенты могли его свободно получать и использовать.
7. Скрипты для обработки XML запросов:
Исходя из договорённости выше, выкладываем их в: /usr/local/apache2-soap/soapagent
Набор скриптов:
soapagent_handler.py — это mod_python handler, который выполняет начальную подготовку и начинает диспетчеризацию XML сервисов.###### soapagent_handler.py ########## from ZSI import dispatch from mod_python import apache import soapagent_services as ss mod = __import__('encodings.utf_8', globals(), locals(), '*') mod = __import__('encodings.utf_16_be', globals(), locals(), '*') def handler(req): # Опция "PythonAutoReload On" из конфига mod_python не перегружает вложенные модули. # В стадии разработки можно добавить принудительню перезагрузку модуля сервисов при каждом запросе. # ВНИМАНИЕ! Это будет происходить при КАЖДОМ запросе! Для продакшин использования это надо выключить! #reload(ss) dispatch.AsHandler(modules=(ss,), request=req) return apache.OK
soapagent_services.py — непосредственно скрипт с реализованными обработчиками.
###### soapagent_services.py ########## from soapagent_server import * # svc: SUM # def SUM(ps): aVal = ps['aVal'] bVal = ps['bVal'] # Здесь мы выполняем какие-то действия cVal = aVal + bVal # А здесь мы возвращаем результат response = SUMResponse() response._result = cVal return response
8. Запускаем Apache:
$ /usr/local/apache2-soap/bin/apachectl startКонфигурация сервера получилась такая:
Server: Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.8d mod_python/3.3.1 Python/2.4.3
9. Для теста можно выполнить клиенский XML запрос:
$ python >>> from ZSI import ServiceProxy >>> service = ServiceProxy.ServiceProxy('http://localhost:8080/wsdl/soapagent.wsdl') >>> service.SUM(aVal=1, bVal=2) {'result': 3}Предполагается, что WSDL файл доступен по адресу: http://localhost:8080/wsdl/soapagent.wsdl
В качестве frontend web-сервера можно использовать и сам python. В библиотеке ZSI кроме mod_python диспетчера «AsHandler» есть еще: AsServer, AsCGI, AsJonPy. Так что можно выбрать по вкусу.
Я выбрал apache. Причины таковы:
- возможность гибко управлять доступом к сервисам (ACL, парольный доступ, SSL и прочее)
- многопоточность получившейся конструкции
- проверенный и надёжный web-сервер, который удобен и знаком обслуживающим его администраторам
- и всё это при достаточно простой схеме установки, настройки и обслуживании ПО









18.05.2008 в 21:44
В примере Apache использует MPM prefork. Опыт показывает, что даже не очень навороченное питоновское приложение легко может занять 20M памяти. И так на каждый апачевский процесс. Если использовать MPM worker, то память здорово экономится. Но надо учесть, что питоновский интерпретатор сможет обрабатывать два запроса параллельно только тогда, когда один из них занят операцией ввода-вывода (например, ждёт ответа от СУБД). Золотую середину можно поискать в конфигурации типа M worker'ов по N потоков. И в таком случае надо быть осторожным с глобальными объектами: они общие на все потоки в одном worker'е. Либо нужно от них отказаться, либо заворачивать их в threading.local.
18.05.2008 в 23:46
Всё именно так! И это надо учитывать. Спасибо за комментарий, const.
Исходя из моего железа и предполагаемой нагрузки на это приложение — MPM prefork мой выбор. Apache в режиме MPM worker и multithreading-safe приложение — отдельный разговор.
26.08.2008 в 15:07
а вы случайно не делали SOAP клиентов на Python с использованием WS Security?
06.09.2008 в 22:52
Привет.
WS Security, когда безопасность на уровне самих сервисов — к сожалению, не делал. А вот безопасность на уровне транспорта (SSL, https) + Basic-аутентификация или аутентификация по SSL сертификатам — делал. ZSI отлично справляется с этим как клиент, а apache — как сервер. оно примерно выглядит.
14.12.2009 в 18:35
Что-то не получается с сервером Апач :(
Пишет:
Traceback (most recent call last):
File "", line 1, in
File «build/bdist.linux-i686/egg/ZSI/ServiceProxy.py», line 324, in __call__
File «build/bdist.linux-i686/egg/ZSI/ServiceProxy.py», line 300, in call_closure
File «build/bdist.linux-i686/egg/ZSI/client.py», line 452, in Receive
File «build/bdist.linux-i686/egg/ZSI/client.py», line 416, in ReceiveSOAP
TypeError: Response is «text/html», not «text/xml»
Где рыть?
14.12.2009 в 20:04
Я бы помотрел для начала вот это: Response is «text/html», not «text/xml»
Это значит, что пришёл не XML ответ, а значит что-то не так. Можно включить трейс запросов и ответов через tracefile=sys.stdout. Или через tcpdump посмотреть запросы и ответы. Думаю, что там (в ответе) будет более понятная диагностика.