WSGI – протокол связи веб-сервера с Python-приложением::Журнал СА 12.2008
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

Российские компании уже несколько лет испытывают дефицит вычислительных мощностей. Рост числа проектов,

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6227
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6933
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4215
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3006
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3807
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3821
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6316
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3170
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3460
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7278
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10646
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12365
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13999
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9124
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7079
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5388
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4617
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3427
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3155
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3402
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3025
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 WSGI – протокол связи веб-сервера с Python-приложением

Архив номеров / 2008 / Выпуск №12 (73) / WSGI – протокол связи веб-сервера с Python-приложением

Рубрика: Веб /  Веб-технологии

Дмитрий Васильев

WSGI – протокол связи веб-сервера
с Python-приложением

Если вы разрабатываете веб-приложение, каркас для разработки веб-приложений или даже веб-сервер на языке Python, вам необходимо знание основ протокола WSGI – стандартного способа связи веб-сервера и веб-приложения.

Долгое время пользователи многих веб-приложений, написанных на Python, были ограничены в выборе веб-серверов, которые они могли использовать совместно с приложениями. Разработчики приложений обычно ограничивались поддержкой одного (изредка – нескольких) способа подключения к веб-серверу. Одни приложения могли использовать CGI, или FastCGI, другие могли быть привязаны к модулю Apache mod_python. Некоторые из приложений могли поддерживать только API, специфичное для одного-единственного сервера. Такая ситуация затрудняла распространение веб-приложений, написанных на Python, и в конце 2003 года впервые был предложен протокол WSGI.

Описание протокола

WSGI (расшифровывается как Web Server Gateway Interface – интерфейс шлюза веб-сервера) – это простой и универсальный интерфейс взаимодействия между веб-сервером и веб-приложением, впервые описанный в PEP-333 (http://www.python.org/dev/peps/pep-0333). Под простотой в данном случае подразумевается лишь простота подключения приложения, но не простота реализации веб-приложений для авторов. Надо заметить, что основной целью разработки WSGI была разработка простого протокола, который мог бы разделить выбор каркасов для разработки веб-приложений от выбора веб-серверов. Это, в частности, позволяет разработчикам приложений (каркасов) и серверов концентрироваться на своей области специализации и отличает WSGI от более общих протоколов связи приложений с веб-серверами, таких как CGI, или FastCGI. С точки зрения WSGI цельное веб-приложение делится на две части: сервер (или шлюз) и непосредственно приложение (или каркас для построения приложений). Для обращения к приложению серверная часть использует вызываемый объект (это может быть функция, метод, класс или экземпляр класса с методом __call__). WSGI также позволяет создавать приложения-посредники, которые являются приложением для веб-сервера и сервером для веб-приложения. Такие посредники могут использоваться для предварительной обработки запросов к приложению или последующей обработки его ответов. Дальше мы рассмотрим несколько примеров использования WSGI и затем обратимся к деталям протокола.

Сторона приложения

Как уже говорилось, приложение – это вызываемый объект, который принимает два аргумента. Приложения должны допускать возможность многократных вызовов, что является обычной ситуацией практически для всех серверов (исключая вызовы с помощью CGI). Далее представлены два примера приложения. Первое приложение реализовано в виде функции:

def simple_app(environ, start_response):

status = '200 OK'

response_headers = [('Content-type','text/plain')]

start_response(status, response_headers)

return ['Hello world!\n']

Здесь функция использует второй аргумент для передачи статуса и заголовков ответа и затем возвращает тело ответа в виде списка строк. Второе приложение реализовано в виде класса:

class AppClass:

 

def __init__(self, environ, start_response):

self.environ = environ

self.start = start_response

 

def __iter__(self):

status = '200 OK'

response_headers = [('Content-type','text/plain')]

self.start(status, response_headers)

yield "Hello world!\n"

В данном случае объект класса будет представлять из себя итератор, который на первом шаге итерации использует второй аргумент для передачи статуса и заголовков ответа и затем вернет тело ответа.

Надо отметить, что приложение с точки зрения WSGI – это всего лишь точка входа, через которую сервер получает доступ к веб-приложению или каркасу для построения веб-приложений.

Сторона сервера

Сервер (или шлюз) будет вызывать приложение для каждого HTTP-запроса, который ему предназначен. Для примера представлен упрощенный шлюз CGI – WSGI. Пример использует упрощенную обработку ошибок, т.к. по умолчанию ошибки будут выдаваться на sys.stderr и затем записываться в лог веб-сервера. Вызываемый объект приложения в данном случае передается как параметр функции:

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()

Посредник: сервер и приложение в одном

Как уже было замечено, некоторые объекты могут играть сразу две роли – быть сервером для какого-либо приложения и приложением для сервера. Вот примеры ситуаций, для которых могут быть полезны WSGI-посредники:

  •   перенаправление запроса на различные приложения, в зависимости от URL после соответствующего изменения environ;
  • возможность запуска нескольких веб-приложений, или каркасов в одном процессе;
  • распределение нагрузки по нескольким сетевым приложениям;
  • обработка ответов приложения, например, с помощью XSL.

Присутствие посредника в большинстве случаев прозрачно и для сервера, и для приложения, более того, посредников можно располагать одного за другим, составляя таким образом «стек посредников».

Детали протокола

Как мы уже видели, приложение должно принимать два аргумента, которые были названы environ и start_response, но могут иметь любые другие имена.

Первый параметр (environ) должен быть объектом словаря (dict) Python и содержит переменные среды, похожие на переменные CGI. Этот объект также должен содержать обязательные для WSGI параметры, которые мы подробнее рассмотрим позже, и может содержать переменные, специфичные для конкретного веб-сервера.

Второй параметр (start_response) – это вызываемый объект, которым приложение предваряет возвращение тела ответа, и принимающий два обязательных параметра и один необязательный. Первый параметр (status) – статус ответа в виде строки, например «200 Ok». Второй параметр (response_headers в примере выше) – список кортежей (tuples) вида (имя_заголовка, значение_заголовка). Третий, необязательный, параметр (exc_info) должен использоваться только при обработке ошибок и должен быть кортежем, который возвращает функция sys.exc_info(). Надо заметить, что start_response не посылает заголовки сразу, а откладывает их до получения первой части тела ответа, чтобы в случае ошибки их можно было заменить на заголовки, сопутствующие ошибке. При этом start_response можно вызывать несколько раз, только если передается третий параметр (exc_info).

После вызова сервером вызываемый объект приложения должен вернуть итерируемый объект, возвращающий ноль, или несколько строк. Как мы видели в предыдущих примерах выше, этого можно достичь несколькими способами, например, вернув список строк, или объект-итератор. При получении очередной части ответа сервер посылает ее клиенту без буферизации, но приложения могут осуществлять буферизацию ответа собственными силами.

В случае если итерируемый объект имеет метод close(), он будет вызван по окончании обработки ответа сервером, даже в случае ошибки. Таким образом метод close() может использоваться для закрытия всех ресурсов приложения, которые могли быть задействованы при создании ответа.

Переменные словаря environ

Словарь environ может содержать следующие CGI переменные (см. таблицу 1).

Таблица 1. Переменные, которые может содержать словарь environ

Имя

Наличие

Описание

REQUEST_METHOD

Обязательный

Метод запроса, например GET или POST

SCRIPT_NAME

Может быть пустым

Начальная порция пути в URL, соответствующая объекту приложения

PATH_INFO

Может быть пустым

Остаток пути в URL, соответствующий цели запроса внутри приложения

QUERY_STRING

Может быть пустым или отсутствовать

Часть URL, которая следует за «?»

CONTENT_TYPE

Может быть пустым или отсутствовать

Содержимое заголовка Content-Type в HTTP-запросе

CONTENT_LENGTH

Может быть пустым или отсутствовать

Содержимое заголовка Content‑Length в HTTP-запросе

SERVER_NAME

Обязательный

Имя сервера

SERVER_PORT

Обязательный

Порт сервера

SERVER_PROTOCOL

Обязательный

Версия протокола, который использует клиент для посылки запроса, например HTTP/1.0 или HTTP/1.1

HTTP_переменные

Необязательны

Переменные, соответствующие заголовкам запроса, переданным клиентом

Также словарь environ должен содержать следующие, обязательные для WSGI, переменные (см. таблицу 2).

Таблица 2. Обязательные для WSGI переменные в словаре environ

Имя

Описание

wsgi.version

Кортеж (1, 0), представляющий версию WSGI – 1.0

wsgi.url_scheme

Строка, представляющая схему из URL, обычно http или https

wsgi.input

Объект, похожий на файл, из которого может быть прочитано тело запроса

wsgi.output

Объект, похожий на файл, в который приложение может выводить сообщения об ошибках

wsgi.multithread

True, если объект приложения может быть одновременно вызван из нескольких потоков

wsgi.multiprocess

True, если соответствующие объекты приложения могут быть одновременно вызваны в нескольких процессах

wsgi.run_once

True, если сервер предполагает (но не гарантирует), что приложение будет вызвано только один раз во время жизни текущего процесса

Плюс environ может содержать специфичные для конкретного сервера переменные и переменные среды. Чтобы увидеть набор переменных, передаваемых приложению, можно использовать, например, следующее простое WSGI-приложение:

def application(environ, start_response):

lines = []

for key, value in environ.items():

lines.append("%s: %r" % (key, value))

start_response("200 OK", [("Content-Type", "text/plain")])

return ["\n".join(lines)]

Обработка ошибок

В общем случае приложение должно обрабатывать внутренние ошибки и выводить соответствующее сообщение клиенту. Конечно, прежде чем выводить сообщение об ошибке, приложение не должно начинать выводить нормальный ответ. Чтобы обойти эту ситуацию, используется третий параметр start_response – exc_info:

try:

# Код обычного приложения

status = "200 OK"

response_headers = [("content-type", "text/plain")]

start_response(status, response_headers)

return ["OK"]

except:

# В реальном коде различные ошибки должны обрабатываться

# различными обработчиками и не должен использоваться пустой except

status = "500 Error"

response_headers = [("content-type", "text/plain")]

start_response(status, response_headers, sys.exc_info())

return ["Error"]

Если приложение еще не начало вывод тела ответа, когда произошло исключение, то вызов start_response в обработчике будет нормальным и клиенту вернется ответ об ошибке. В случае если на момент ошибки уже был начат вывод ответа, start_response выкинет переданное исключение. Это исключение не должно обрабатываться обработчиком, а будет обработано сервером и записано в журнал ошибок.

Заключение

На данный момент подавляющее большинство серверов и каркасов для создания веб-приложений поддерживает WSGI. В качестве примера можно привести большое количество серверов, написанных на Python, в том числе веб-сервер из пакета Twisted (http://twistedmatrix.com/trac), а также адаптеры для CGI и FastCGI, модули для Apache и nginx. В качестве примера каркасов могут быть наиболее известные – Django, TurboGears и Pylons. Более полный список и последнюю информацию по WSGI можно получить на сайте http://www.wsgi.org.

Описание работы WSGI, изложенное в этой статье, должно помочь в лучшем понимании готовых веб-приложений, написанных с использованием этого протокола, а также в написании собственных веб-приложений и серверов.

Приложение

Пакет wsgiref

В стандартной библиотеке Python 2.5 появился новый пакет wsgiref, предоставляющий различные утилиты для упрощения работы с WSGI. Рассмотрим кратко его содержимое:

  • wsgiref.util – содержит функции для работы со словарем environ. Например, функцию для сборки полного URL из переменных environ;
  • wsgiref.headers – содержит класс для упрощения работы с заголовками ответа в виде объекта, похожего на словарь;
  • wsgiref.simple_server – содержит функции и классы для создания простого WSGI-сервера и демонстрационного приложения;
  • wsgiref.validate – содержит функцию-обертку, проверяющую WSGI-приложение и сервер на соответствие WSGI-спецификации;
  • wsgiref.handlers – содержит базовые классы для создания WSGI-серверов.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru