Язык программирования Python
Шрифт:
И, наконец, фаза вывода готового объекта (текста, HTML–документа, изображения, мультимедиа–объекта и т.п.). Проще всего заранее подготовить шаблон страницы (или ее крупных частей), а потом просто заполнить содержимым из переменных.
В приведенных примерах имена появлялись в строке запроса только один раз. Некоторые формы порождают несколько значений для одного имени. Получить все значения можно с помощью метода getlist:
Листинг
lst = form.getlist(«fld»)
Список lst будет содержать столько значений, сколько полей с именем fld получено из web–формы (он может быть и пустым, если ни одно поле с заданным именем не было заполнено).
В некоторых случаях
Листинг
#!/usr/bin/env python
import cgi
form = cgi.FieldStorage
file_contents = ""
if form.has_key(«filename»):
fileitem = form[«filename»]
if fileitem.file:
file_contents = """Содержимое переданного файла:
<PRE>%s</PRE>""" % fileitem.file.read
print ""«Content–Type: text/html
<HTML><HEAD><TITLE>Загрузка файла</TITLE></HEAD>
<BODY><H1>Загрузка файла</H1>
<FORM ENCTYPE=«multipart/form–data»
ACTION=«getfile.cgi» METHOD=«POST»>
<br>Файл: <INPUT TYPE=«file» NAME=«filename»>
<br><INPUT TYPE=«submit» NAME=«button» VALUE=«Передать файл»>
</FORM>
%s
</BODY></HTML>""" % file_contents
В начале следует рассмотреть web–форму, которая приведена в конце сценария: именно она будет выводиться пользователю при обращении по CGI–сценарию. Форма имеет поле типа file, которое в web–броузере представляется полоской ввода и кнопкой «Browse». Нажимая на кнопку «Browse», пользователь выбирает файл, доступный в ОС на его компьютере. После этого он может нажать кнопку «Передать файл» для передачи файла на сервер.
Для отладки CGI–сценария можно использовать модуль cgitb. При возникновении ошибки этот модуль выдаст красочную HTML–страницу с указанием места возбуждения исключения. В начале отлаживаемого сценария нужно поставить
Листинг
import cgitb
cgitb.enable(1)
Или, если не нужно показывать ошибки в браузере:
Листинг
import cgitb
cgitb.enable(0, logdir="/tmp»)
Только необходимо помнить, что следует убрать эти строки, когда сценарий будет отлажен, так как он выдает кусочки кода сценария. Это может быть использовано злоумышленниками, с тем чтобы найти уязвимости в CGI–сценарии или подсмотреть пароли (если таковые присутствуют в сценарии).
Что после CGI?
К сожалению, строительство интерактивного и посещаемого сайта на основе CGI имеет свои ограничения, главным образом, связанные с производительностью. Ведь для каждого запроса нужно вызвать как минимум один сценарий (а значит — запустить интерпретатор Python), из него, возможно, сделать соединение с базой данных и т.д. Время запуска интерпретатора Python достаточно невелико, тем не менее, на занятом сервере оно может оказывать сильное влияние на загрузку процессора.
Желательно, чтобы интерпретатор уже находился в оперативной памяти, и были доступны соединения с базой данных.
Такие технологии существуют и обычно опираются на модули, встраиваемые в web–сервер.
Для ускорения работы CGI используются различные схемы, например, FastCGI или PCGI (Persistent CGI). В данной лекции предлагается к рассмотрению специальным модуль для web–сервера Apache, называемый mod_python.
Пусть модуль установлен на web–сервере в соответствии с инструкциями, данными в его документации.
Модуль mod_python
позволяет сценарию–обработчику вклиниваться в процесс обработки HTTP–запроса сервером Apache на любом этапе, для чего сценарий должен иметь определенным образом названные функции.Сначала нужно выделить каталог, в котором будет работать сценарий–обработчик. Пусть это каталог /var/www/html/mywebdir. Для того чтобы web–сервер знал, что в этом каталоге необходимо применять mod_python, следует добавить в файл конфигурации Apache следующие строки:
Листинг
<Directory "/var/www/html/mywebdir»>
AddHandler python–program .py
PythonHandler mprocess
</Directory>
После этого необходимо перезапустить web–сервер и, если все прошло без ошибок, можно приступать к написанию обработчика mprocess.py. Этот сценарий будет реагировать на любой запрос вида http://localhost/*.py.
Следующий сценарий mprocess.py выведет в браузере страницу со словами Hello, world!:
Листинг
from mod_python import apache
def handler(req):
req.content_type = «text/html»
req.send_http_header
req.write("""<HTML><HEAD><TITLE>Hello, world!</TITLE></HEAD>
<BODY>Hello, world!</BODY></HTML>""")
return apache.OK
Отличия сценария–обработчика от CGI–сценария:
Сценарий–обработчик не запускается при каждом HTTP–запросе: он уже находится в памяти, и из него вызываются необходимые функции–обработчики (в приведенном примере такая функция всего одна — handler). Каждый процесс–потомок web–сервера может иметь свою копию сценария и интерпретатора Python.
Как следствие п.1 различные HTTP–запросы делят одни и те же глобальные переменные. Например, таким образом можно инициализировать соединение с базой данных и применять его во всех запросах (хотя в некоторых случаях потребуются блокировки, исключающие одновременное использование соединения разными потоками (нитями) управления).
Обработчик задействуется при обращении к любому «файлу» с расширением py, тогда как CGI–сценарий обычно запускается при обращении по конкретному имени.
В сценарии–обработчике нельзя рассчитывать на то, что он увидит модули, расположенные в том же каталоге. Возможно, придется добавить некоторые каталоги в sys.path.
Текущий рабочий каталог (его можно узнать с помощью функции os.getcwd) также не находится в одном каталоге с обработчиком.
#! — строка в первой строке сценария не определяет версию интерпретатора Python. Работает версия, для которой был скомпилирован mod_python.
Все необходимые параметры передаются в обработчик в виде Request–объекта. Возвращаемые значения также передаются через этот объект.
Web–сервер замечает, что сценарий–обработчик изменился, но не заметит изменений в импортируемых в него модулях. Команда touch mprocess.py обновит дату изменения файла сценария.
Отображение os.environ в обработчике может быть обрезанным. Кроме того, вызываемые из сценария–обработчика другие программы его не наследуют, как это происходит при работе с CGI–сценариями. Переменные можно получить другим путем: req.add_common_vars; params = req.subprocess_env.
Так как сценарий–обработчик не является «одноразовым», как CGI–сценарий, из–за ошибок программирования (как самого сценария, так и других компонентов) могут возникать утечки памяти (программа не освобождает ставшую ненужной память). Следует установить значение параметра MaxRequestsPerChild (максимальное число запросов, обрабатываемое одним процессом–потомком) больше нуля.