Building a Web Services in Python
Поднимаем XML на Пайтоне
1. Python:
В системе должен быть установлен , версии не ниже 2.3
2. Устанавливаем apache ( ):
$ ./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 ( )
$ ./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 ( ):
Берём ZSI не ниже версии , 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 посмотреть запросы и ответы. Думаю, что там (в ответе) будет более понятная диагностика.
03.10.2010 в 13:31
У меня такая же ошибка
Я добавил print client.py а там действительно хтмл:
>>> service = ServiceProxy.ServiceProxy ('http://localhost/wsdl/soapagent.wsdl')
>>> service.SUM (aVal=1, bVal=2)
**************************
None
**************************
False
**************************
301 Moved Permanently
Moved Permanently
The document has moved .
Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/2.5.2 Server at localhost Port 80
**************************
Traceback (most recent call last):
File "", line 1, in
File «build/bdist.linux-x86_64/egg/ZSI/ServiceProxy.py», line 324, in __call__
File «build/bdist.linux-x86_64/egg/ZSI/ServiceProxy.py», line 300, in call_closure
File «build/bdist.linux-x86_64/egg/ZSI/client.py», line 459, in Receive
File «build/bdist.linux-x86_64/egg/ZSI/client.py», line 423, in ReceiveSOAP
TypeError: Response is «text/html», not «text/xml»
>>>
Я так и не понял откуда это
03.10.2010 в 13:50
Это от того, что вместо ответа Апач прислал вам редирект «301 Moved Permanently». Смотрите на конфигурацию Апача, что-то там сконфигурено не так, как надо.
03.10.2010 в 15:08
http.conf:
SetHandler mod_python
PythonPath ['/var/www/soapagent']«+sys.path»
PythonHandler soapagent_handler
PythonAutoReload On
PythonDebug On
soapagent_handler.py находится в /var/www/soapagent/ здесь же находиться
soapagent_client.py
soapagent_handler.py
soapagent_server.py
soapagent_services.py
soapagent_types.py
soapagent.wsdl находиться в /var/www/wsdl/ и в нём адрес
У меня Убунту 8.04 Апаче 2.2 Python 2.5
Я протестировал mod_python он работает отлично
03.10.2010 в 15:09
Буду очень признателен если поможете разобраться
03.10.2010 в 15:37
Сначала стоит посмотреть в ваш . А именно в секцию вида:
<soap :address location="http://xxxxxxxxxxxxxxxxxxxxx">
</soap>
Именно этот URL вызывается при обращении в сервису. Далее я бы сделал: wget и посмотрел ответ Апача. Скорее всего он должен ответить вам тем же, что вы привели выше: «301 Moved Permanently» А далее, смотря на этот URL и на ваш конфиг Апача, понять что не так.
Выше вы привели часть вашего http.conf. Но из неё, к сожалению, много не понятно. То что вы привели находится прямо в основном конфиге или принадлежит какому-то вирт.хосту? Этот soapagent_handler принадлежит всему хосту или какому-то locaton? Соответствует ли этот location URL-у, указанному в вашем wsdl?
03.10.2010 в 17:58
с помошью wget получаеться скачать файл
В http.conf-е находиться
SetHandler mod_python
PythonHandler mod_python.testhandler
SetHandler mod_python
PythonPath ['/var/www/soapagent']«+sys.path»
PythonHandler soapagent_handler
PythonAutoReload On
PythonDebug On
mpinfo работает так работает если его заменить другим питоновским файлом с «Hello World»-ом
VirtalHost находиться в другом файле
/etc/apache2/sites-available/default
И если я правильно понял soap_handler принадлежить основному хосту
03.10.2010 в 18:02
не получаеться писать с тегами
--Location /mpinfo
SetHandler mod_python
PythonHandler mod_python.testhandler
--Location
--Location /soapagent
SetHandler mod_python
PythonPath ['/var/www/soapagent']«+sys.path»
PythonHandler soapagent_handler
PythonAutoReload On
PythonDebug On
--Location
service name="soapagent"
port name="soapagentPort" binding="tns:soapagentPort"
soap:address location="http://localhost/soapagent"
/soap:address
/port
/service
03.10.2010 в 19:13
Что происходит при: wget Особенно обратите внимание происходит ли редирект на: (слэш в конце).
03.10.2010 в 19:58
Получаеться вот что:
bayasaa@bayasaa-desktop:~$ wget
--23:55:37--
=> `index.html'
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 500 Internal Server Error
23:55:39 ERROR 500: Internal Server Error.
А на браузере:
Traceback (most recent call last):
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 1537, in HandlerDispatch
default=default_handler, arg=req, silent=hlist.silent)
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 1202, in _process_target
module = import_module (module_name, path=path)
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 304, in import_module
return __import__ (module_name, {}, {}, ['*'])
File «/var/www/soapagent/soapagent_handler.py», line 6, in
import soapagent_services as ss
File «/var/www/soapagent/soapagent_services.py», line 2, in
from soapagent_server import *
File «/var/www/soapagent/soapagent_server.py», line 38, in
class soapagent (ServiceSOAPBinding):
File «/var/www/soapagent/soapagent_server.py», line 50, in soapagent
root[(SUM.typecode.nspname,SUM.typecode.pname)] = 'soap_SUM'
AttributeError: class SUM has no attribute 'typecode'
03.10.2010 в 20:06
На браузере вот это:
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 1537, in HandlerDispatch
default=default_handler, arg=req, silent=hlist.silent)
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 1229, in _process_target
result = _execute_target (config, req, object, arg)
File «/usr/lib/python2.5/site-packages/mod_python/importer.py», line 1128, in _execute_target
result = object (arg)
File «/var/www/soapagent/soapagent_handler.py», line 12, in handler
dispatch.AsHandler (modules=(ss,), request=req)
File «build/bdist.linux-x86_64/egg/ZSI/dispatch.py», line 271, in AsHandler
ps = ParsedSoap (request)
File «build/bdist.linux-x86_64/egg/ZSI/parse.py», line 64, in __init__
self.dom = self.reader.fromStream (input)
File «/usr/lib/python2.5/xml/dom/expatbuilder.py», line 928, in parse
result = builder.parseFile (file)
File «/usr/lib/python2.5/xml/dom/expatbuilder.py», line 211, in parseFile
parser.Parse ("", True)
ExpatError: no element found: line 1, column 0
03.10.2010 в 20:22
Замените в вашем WSDL вот это:
soap:address location="http://localhost/soapagent"
на это:
soap:address location="http://localhost/soapagent/"
(слэш в конце добавить)
И попробовать вызвать сервис клиентом.
03.10.2010 в 20:47
Ураа. Получился
Спасибо
Я первый раз имею дело с SOAP-ом, так что не обесудьте за ламерство
Теперь перейпу на 2ую часть