Попробуем реализовать web-приложение на базе wsgi без использования фреймворков django, flask и пр. Потому, что, зачастую, использование подобных универсальных инструментов в небольших проектах приводит к излишнему усложнению.
Исходные положения
Структуру web-приложения будем строить исходя из аксиомы, что имеется только одна точка доступа к функционалу приложения. Это скрипт-роутер.
Назначение скрипта-роутера
Выполняет только следующие задачи:
- определяет набор комманд web-приложения, доступный пользователям,
- извлекает из запросов (GET и POST) команды, параметры и их значения,
- проверяет права пользователей на выполнение команды web-приложения, поступившей в запросе,
- перенаправляет команду на выполнение соотвествующей функции
- преобразует результат выполнения функции в единую унифицированную структуру ответа и возвращает его клиенту, отправившему запрос.
Такой функционал скрипта-роутера подразумевает определенную организацию всего web-приложения
Организация web-приложения
Адресация
Прежде всего, необходим URL по которому будет запускаться скрипт-роутер. На этапе настройки web-приложения этот путь задается в конфигурации (виртуального хоста). Договоримся, что вызов скрипта-роутера будет выполняться по запросу http://site.name/command. "command", в данном случае, это префикс роутер.
Далее, запрос должен содержать команду web-приложения, которую хочет выполнить пользователь и ее параметры. Примем следующий синтаксис http://site.name/command/commandName/function/subfunction/../func?p1=n1&p2=n2...
Т.е. запрос после префикса разбивается на три части:
- имя команды
- последовательность вложенных подкоманд
- набор параметров со значениями
Реализация команд web-приложения
Команды реализуются через функции, которые подключаются к скрипту-роутеру Из предыдущего пункта естественно вытекает первое требование к таким функциям. Не сильно жесткое. Функция должна принимать три входных параметра:
- последовательность вложенных подкоманд. Параметр может быть пустым
- набор параметров функции типа ключ-значение. Данный параметр также может быть пустым.
- параметр переменных окружения. Часто они бывают нужны для работы функций
Второе требование к функции - возвращаемое значение должно принадлежать к одному из типов:
1) Если в результате работы функция возвращает 'отрицательный' ответ, то это - словарь с двумя ключами: - type_message - ("error" - текстовое сообщение об ошибке, "debug" - отладочная и контрольная информация, ...) - message - данные, соотвествующие значению type_message
Данный тип рекомендуется для унификации обработки ответа на стороне клиента
- Функция может возвращать следующие объекты - число, строка, массив, кортеж, словарь. Корректное вложение этих объектов в ответ для клиента возложена на скрипт-роутер.
- Словарь, содержащий непосредственно результат работы функции и дополнительные параметры, переопределяющие значения http заголовка ответа по умолчанию.
Структура ответа
Отправив запрос на выполнение команды web-приложения пользователь ожидает ответа положительного или отрицательного. Поэтому договоримся, что на стороне сервера формируется ответ структуры словаря со сдежующими обязательными ключами
- '__status' - статус ответа, возвращаемого клиенту (текстовый параметр)
- '__headers' - заголовки ответа клиенту: массив кортежей из пары (имя параметра заголовка, значение параметра)
- 'data' - строка возвращаемых данных от прикладной функции
В скрипте- роутере определяются значения '__headers' и '__status' по умолчанию, достаточные для передачи ответа пользователю по HTTP. Результат работы команды присваивается ключу 'data' и ответ отправляется пользователю.
Если функции, необходимо изменить значение '__headers' или '__status', тогда функция должна возвращать не просто результаты своей работы, но и необходимые значения изменяемых ключей.
Безопасность
В рамках темы публикации вопрос безопасности web-приложения будем рассматривать только в контексте проверки права пользовательского запроса на выполнение команды web-приложения. Но даже в этом случае не берусь настаивать на какой-либо конкретной реализации проверки и интегрировать ее в скрипт-роутер. Поэтому примем соглашение, что проверка права запроса на выполнение команды выполняется функцией, возвращающей True в случае успеха и False - если проверка права не пройдена.
Производительность
В проекте
Пример wsgi-скрипта, реализующего функции скрипта-роутера в соотвествии с указанными выше требованиями, можно скачать здесь. Пояснения по ключевым вопросам приведены в комментариях скрипта.