- 1. lighttpd mod_cgi и простой скрипт
- 2. web.py на порту 8080
- 3. WCGI интерфейс
- 4. Простой сервер WSGI
- 5. WSGI с использованием wsgiref
- 6. WSGI c помощью flup
- 7. web.py приложение с использованием flup
- 8. Немного особенностей
1. Для решения задачи «в лоб» был поднят lighttpd c mod_cgi:
sudo apt-get install lighttpd
sudo nano /etc/lighttpd/lighttpd.conf
Отрывок lighttpd.conf:
#mod_cgi shoud be on
server.modules = (
"mod_access",
"mod_alias",
"mod_compress",
"mod_redirect",
"mod_cgi",
"mod_rewrite",
)
#rule enables cgi script
cgi.assign = (".py" => "/usr/bin/python")
/var/www/index.py:
print "Content-Type: text/html\n\n"
print "Hello World!"
теперь localhost/index.py отвечал бодрым «Hello World!»
Когда lighttpd встречает файл с расширением .py передает его на выполнение python-у и его результатом отвечает на запрос. Грубо говоря перенаправляет stdout.
После некоторых попыток написания интерфейса «с нуля», был рожден HtmlGenerator, который позволил не перегружать код html-тегами, весьма упростил, но все таки не решил проблемы в комплексе.
2. Решено было поэкспериментировать с веб фреймворками.
Под руку попался wep.py, простенький и маловесный.
code.py:
#! /usr/bin/python
#
import web
urls = ( '/', 'index',)
class index:
def GET(self):
return "Hello, world!"
if __name__ == "__main__":
web.application(urls, globals()).run()
Минимальный код и на порту 8080 висит наше веб приложение
Казалось бы пробросить алиас на порт 8080, организовать авто запуск скрипта и все готово.
Да но нет, эксперименты на слабеньком компьютере показали что присутствие нашего скрипта заставляет машинку изрядно «дуться». Кроме того есть lighttpd с mod_cgi.
Как же связать простой скрипт и веб приложение.
3. Согласно описанию WSGI, для его реализации необходим интерфейс такого вида
#! /usr/bin/python
#
def myapp(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello World!\n']
Ничего военного, но и что-то не работает, чего-то не хватает.
Момент который был неясным после прочтения вики и других статей, что же все таки запустит наш интерфейс.
4. Для запуска WSGI приложения нужен сервер. Пример скрипта который может выступать в роли простого сервера WSGI:
wsgi.py:
#! /usr/bin/python
import os
import sys
def run_with_cgi(application):
environ = dict(os.environ.items())
environ['wsgi.input'] = sys.stdin
environ['wsgi.errors'] = sys.stderr
environ['wsgi.version'] = (1, 0)
environ['wsgi.multithread'] = False
environ['wsgi.multiprocess'] = True
environ['wsgi.run_once'] = True
if environ.get('HTTPS', 'off') in ('on', '1'):
environ['wsgi.url_scheme'] = 'https'
else:
environ['wsgi.url_scheme'] = 'http'
headers_set = []
headers_sent = []
def write(data):
if not headers_set:
raise AssertionError("write() before start_response()")
elif not headers_sent:
status, response_headers = headers_sent[:] = headers_set
sys.stdout.write('Status: %s\r\n' % status)
for header in response_headers:
sys.stdout.write('%s: %s\r\n' % header)
sys.stdout.write('\r\n')
sys.stdout.write(data)
sys.stdout.flush()
def start_response(status, response_headers, exc_info=None):
if exc_info:
try:
if headers_sent:
raise exc_info[0], exc_info[1], exc_info[2]
finally:
exc_info = None
elif headers_set:
raise AssertionError("Headers already set!")
headers_set[:] = [status, response_headers]
return write
result = application(environ, start_response)
try:
for data in result:
if data:
write(data)
if not headers_sent:
write('')
finally:
if hasattr(result, 'close'):
result.close()
Теперь добавив к нашему интерфейсу его запуск получим скрипт который ответит уже на нашем lighttpd или apache, по адресу localhost/app.py
/var/www/app.py:
#! /usr/bin/python
include wsgi
def myapp(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello World!\n']
if __name__ == '__main__':
wsgi.run_with_cgi(myapp)
5. Для python 2.7 доступен модуль wsgiref который может реализовать WSGI сервер
#! /usr/bin/python
import wsgiref.handlers
def myapp(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello World!\n']
if __name__ == '__main__':
wsgiref.handlers.CGIHandler().run(myapp)
6. Реализация WSGI c помощью flup:
установим flup
sudo apt-get install python-flup
#! /usr/bin/python
import flup.server.fcgi
def myapp(environ, start_response):
status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello World!\n']
if __name__ == '__main__':
flup.server.fcgi.WSGIServer(myapp).run()
7. Простое web.py приложение с использованием flup:
/var/www/app.py:
#! /usr/bin/python
import web
urls = ( '/', 'index', )
class index:
def GET(self):
return "Hello World!"
if __name__ == '__main__':
web.application(urls, globals()).run()
приложение станет доступным по адресу localhost/app.py
8. По умолчанию web.py использует flup, но можно обойтись и без него.
Для запуска web.py на wsgiref необходимо:
web.application(urls, globals()).cgirun()
B ссылках на скрипты web.py в конце не забывать ставить '/' (app.py/), иначе ответом будет «not found». По-хорошему необходимо создать rewrite правило:
# mod_rewrite configuration.
url.rewrite-once = (
"^/favicon.ico$" => "/favicon.ico",
"^/(.*)$" => "app.py/$1" ,)
Для отладки в скриптов полезно добавить:
import cgitb
cgitb.enable()
тогда будут видны ошибки.
Остается опробовать:
modwsgi
paste
pylons
Полезные ссылки:
WSGI wiki
wep.py
WSGI — протокол связи Web-сервера с Python приложением
WSGI, введение
How to serve a WSGI application via CGI
WSGI.org
Сравнение эффективности способов запуска веб-приложений на языке Python
Комментарии (10)
kAIST
24.04.2015 01:06+1После некоторых попыток написания интерфейса «с нуля», был рожден HtmlGenerator, который позволил не перегружать код html-тегами, весьма упростил, но все таки не решил проблемы в комплексе.
А чем родной шаблонизатор из того же web.py не угодил?
Я на той же малинке запускаю тот же web.py без стороннего сервера (через cherrypy насколько я знаю работает), просто:
sudo python code.py 80
Для текущих задач вполне хватает.tarasii Автор
24.04.2015 14:27Я упоминал что просто запустив скрипт c приложением web.py запускается и сервер на порту по умолчанию 8080.
При таком запуске web.py не находит должного окружения и запускает «свой» WSGI сервер позаимствованный у cherrypy фреймворка. Поднять http сервер на питоне — не очень сложная задача. Фреймворки у себя под юбкой прячут уйму интересного. HtmlGenerator написан для моего удобства, на фреймворк он явно не тянет. Там нет ни рендеренга шаблонов, ни сессий ничего просто «помагатор», которого вполне хватает чтоб выдать данные на просмотр:
print(mh.Html("MyHtml", mh.JavaScript("console.log('start');"),mh.Header("Main:"),"")
Никаких фреймворков все бысто и просто.
Jekel
24.04.2015 13:08А я то думал тут будет что-то про Raspberry Pi кроме упоминания в первой строке.
Про то как писать и запускать wsgi скрипты написано миллион и одна статья, зачем еще одна?vit1251
26.04.2015 16:10Я думаю, что не хватает оглавления (индекса), но это просто не полное.
Так что не вините автора он хорошее дело делает.
bromzh
25.04.2015 03:21Зачем использовать CGI, если у питона есть свой протокол (WSGI) и довольно быстрые серверы (UWSGI/gevent/etc, например, вот их сравнение). В рамках такого проекта можно не ставить nginx/apache/lighttpd, а использовать питоновский сервер напрямую.
Ну и советую рассмотреть фреймворки, типа flask или bottle. Последний удобен тем, что занимает 1 файл, его легко подключить в небольшой проект, без установки зависимостей. Всего 2 файла (плюс немного шаблонов), интерпретатор, и простенький веб-интерфейс готов.
Pavel_Osipov
А из этого ничего не пробовали?
Twisted
Tornado Web Server
cyclone.io
Весьма удобные штуки
un_def
CherryPy
Flask
…
______ (впишите свой фреймворк/веб-сервер)