Язык программирования Python

       

Что после 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-сценария:

  1. Сценарий- обработчик не запускается при каждом HTTP-запросе: он уже находится в памяти, и из него вызываются необходимые функции-обработчики (в приведенном примере такая функция всего одна - handler()). Каждый процесс-потомок web-сервера может иметь свою копию сценария и интерпретатора Python.
  2. Как следствие п.1 различные HTTP-запросы делят одни и те же глобальные переменные. Например, таким образом можно инициализировать соединение с базой данных и применять его во всех запросах (хотя в некоторых случаях потребуются блокировки, исключающие одновременное использование соединения разными потоками (нитями) управления).
  3. Обработчик задействуется при обращении к любому "файлу" с расширением py, тогда как CGI-сценарий обычно запускается при обращении по конкретному имени.
  4. В сценарии-обработчике нельзя рассчитывать на то, что он увидит модули, расположенные в том же каталоге. Возможно, придется добавить некоторые каталоги в sys.path.
  5. Текущий рабочий каталог (его можно узнать с помощью функции os.getcwd()) также не находится в одном каталоге с обработчиком.
  6. #!-строка в первой строке сценария не определяет версию интерпретатора Python. Работает версия, для которой был скомпилирован mod_python.
  7. Все необходимые параметры передаются в обработчик в виде Request-объекта. Возвращаемые значения также передаются через этот объект.
  8. Web-сервер замечает, что сценарий-обработчик изменился, но не заметит изменений в импортируемых в него модулях. Команда touch mprocess.py обновит дату изменения файла сценария.
  9. Отображение os.environ в обработчике может быть обрезанным. Кроме того, вызываемые из сценария-обработчика другие программы его не наследуют, как это происходит при работе с CGI-сценариями. Переменные можно получить другим путем: req.add_common_vars(); params = req.subprocess_env.
  10. Так как сценарий-обработчик не является "одноразовым", как CGI-сценарий, из-за ошибок программирования (как самого сценария, так и других компонентов) могут возникать утечки памяти (программа не освобождает ставшую ненужной память).


    Следует установить значение параметра MaxRequestsPerChild (максимальное число запросов, обрабатываемое одним процессом-потомком) больше нуля.


Другой возможный обработчик - сценарий идентификации:

def authenhandler(req): password = req.get_basic_auth_pw() user = req.connection.user if user == "user1" and password == "secret": return apache.OK else: return apache.HTTP_UNAUTHORIZED



Эту функцию следует добавить в модуль mprocess.py, который был рассмотрен ранее. Кроме того, нужно дополнить конфигурацию, назначив обработчик для запросов идентификации (PythonAuthenHandler), а также обычные для Apache директивы AuthType, AuthName, require, определяющие способ авторизации:

<Directory "/var/www/html/mywebdir"> AddHandler python-program .py PythonHandler mprocess PythonAuthenHandler mprocess AuthType Basic AuthName "My page" require valid-user </Directory>

Разумеется, это - всего лишь пример. В реальности идентификация может быть устроена намного сложнее.

Другие возможные обработчики (по документации к mod_python можно уточнить, в какие моменты обработки запроса они вызываются):

PythonPostReadRequestHandler

Обработка полученного запроса сразу после его получения.

PythonTransHandler

Позволяет изменить URI запроса (в том числе имя виртуального сервера).

PythonHeaderParserHandler

Обработка полей запроса.

PythonAccessHandler

Обработка ограничений доступа (например, по IP-адресу).

PythonAuthenHandler

Идентификация пользователя.

PythonTypeHandler

Определение и/или настройка типа документа, языка и т.д.

PythonFixupHandler

Изменение полей непосредственно перед вызовом обработчиков содержимого.

PythonHandler

Основной обработчик запроса.

PythonInitHandler

PythonPostReadRequestHandler или PythonHeaderParserHandler в зависимости от нахождения в конфигурации web-сервера.

PythonLogHandler

Управление записью в логи.

PythonCleanupHandler

Обработчик, вызываемый непосредственно перед уничтожением Request-объекта.

Некоторые из этих обработчиков работают только глобально, так как при вызове даже каталог их приложения может быть неизвестен (таков, например, PythonPostReadRequestHandler).

С помощью mod_python можно строить web-сайты с динамическим содержимым и контролировать некоторые аспекты работы web-сервера Apache через Python-сценарии.


Содержание раздела