Не так давно появилась спецификация интерфейса между web-серверами и приложениями/фреймворками на perl PSGI — Perl Web Server Gateway Interface Specification. PSGI добавляет слой абстракции, позволяющий не заботиться о конкретном способе подключения к web-серверу, и реализовать единственный интерфейс для спецификации. Запустить такое приложение можно на cерверах, поддерживающих PSGI — на данный момент это Plack (набор серверов и утилит), nginx (с патчем для поддержки PSGI и встроенным perl) и Apache с mod_psgi.
PSGI-приложение представляет собой функцию, принимающую в качестве аргумента ссылку на хэш с переменными окружения, и возвращающую ответ.
Хэш, передаваемый в приложение, содержит переменные, имена которых аналогичны именам заголовков в CGI — REQUEST_METHOD, SCRIPT_NAME, QUERY_STRING и т.д., а также заголовки из HTTP-запроса (начинаются с HTTP_, например HTTP_HOST). Кроме этого, хэш должен содержать PSGI-специфичные переменные:
В общем случае приложение должно вернуть ссылку на массив из трех элементов — HTTP-код ответа, заголовки и тело ответа. HTTP-код ответа должен быть целым числом не менее 100. Заголовки передаются в виде ссылки на массив, причем заголовок Content-Type должен присутствовать обязательно (кроме ответов 1xx, 204 или 304). Телом ответа может являться ссылка на массив строк (или весь ответ без построчного разделения), либо IO::Handle-подобный объект или файловый дескриптор. Если требуется отложенный ответ, приложение может вернуть функцию, в которую будет передан колбэк для ответа.
Так выглядит простейшее PSGI-приложение:
Middleware похоже на обычное приложение, но принимает 2 аргумента — переменные окружения и ответ PSGI-приложения. Middleware может применяться для анализа этих данных (например, обычное ведение access log) или их модификации. Вот пример middleware, добавляющего в ответ заголовок X-PSGI-Used:
Для Plack на CPAN существует довольно большой набор разнообразных middleware.
Сервер обеспечивает запуск PSGI-приложения и должен составлять хэш с переменными окружения и передавать его в приложение, а также обрабатывать ответ. Сейчас существует несколько PSGI-серверов:
Сейчас есть поддержка PSGI во всех популярных web-фреймворках: Catalyst, CGI::Application, HTTP::Engine, Dancer, Mason, Squatting, Continuity, Maypole, Tatsumaki
Сайт PSGI/Plack
Спецификация PSGI на CPAN
PSGI::FAQ
Plack на CPAN
Приложения
PSGI-приложение представляет собой функцию, принимающую в качестве аргумента ссылку на хэш с переменными окружения, и возвращающую ответ.
Запрос
Хэш, передаваемый в приложение, содержит переменные, имена которых аналогичны именам заголовков в CGI — REQUEST_METHOD, SCRIPT_NAME, QUERY_STRING и т.д., а также заголовки из HTTP-запроса (начинаются с HTTP_, например HTTP_HOST). Кроме этого, хэш должен содержать PSGI-специфичные переменные:
- psgi.version: Ссылка на массив [1,0], содержащий версию PSGI.
- psgi.url_scheme: http или https, в зависимости от запроса.
- psgi.input: поток ввода.
- psgi.errors: поток для вывода ошибок.
- psgi.multithread: true, если приложение может быть вызвано в другом потоке того же процесса.
- psgi.multiprocess: true, если приложение может быть вызвано в другом процессе.
- psgi.run_once: true, если ожидается (но не гарантируется), что приложение будет вызвано только один раз до завершения процесса (обычно true только если приложение подключено к серверу через CGI).
- psgi.nonblocking: true, если приложение вызывается в event loop.
- psgi.streaming: true, если сервер поддерживает отложенные ответы и streaming.
Ответ
В общем случае приложение должно вернуть ссылку на массив из трех элементов — HTTP-код ответа, заголовки и тело ответа. HTTP-код ответа должен быть целым числом не менее 100. Заголовки передаются в виде ссылки на массив, причем заголовок Content-Type должен присутствовать обязательно (кроме ответов 1xx, 204 или 304). Телом ответа может являться ссылка на массив строк (или весь ответ без построчного разделения), либо IO::Handle-подобный объект или файловый дескриптор. Если требуется отложенный ответ, приложение может вернуть функцию, в которую будет передан колбэк для ответа.
Пример приложения
Так выглядит простейшее PSGI-приложение:
sub {[200, ['Content-Type' => 'text/plain'], ['Hi, ' . shift->{REMOTE_ADDR}]]}
Middleware
Middleware похоже на обычное приложение, но принимает 2 аргумента — переменные окружения и ответ PSGI-приложения. Middleware может применяться для анализа этих данных (например, обычное ведение access log) или их модификации. Вот пример middleware, добавляющего в ответ заголовок X-PSGI-Used:
my $app = sub {[200, ['Content-Type' => 'text/plain'], ['Hi, ' . shift->{REMOTE_ADDR}]]}<br/>
my $middleware = sub {<br/>
my $env = shift;<br/>
my $res = $app->($env);<br/>
push @{$res->[1]}, 'X-PSGI-Used' => 1;<br/>
return $res;<br/>
};
Для Plack на CPAN существует довольно большой набор разнообразных middleware.
Серверы
Сервер обеспечивает запуск PSGI-приложения и должен составлять хэш с переменными окружения и передавать его в приложение, а также обрабатывать ответ. Сейчас существует несколько PSGI-серверов:
- Plack — набор middleware и серверов, в большинстве своем являющихся врапперами над существующими Perl-модулями. Кроме того, существует несколько серверов в том же пространстве имен, не присутствующих в составле дистрибутива Plack на CPAN: AnyEvent, FCGI::EV, Danga::Socket, Coro, POE и ServerSimple. Запустить PSGI-приложение на Plack просто:
plackup --server Coro --port 9090 --host 127.0.0.1 test.psgi
- nginx с патчем для поддержки psgi
- mod_psgi для Apache
- Perlbal
- некоторые другие серверы
Поддержка фреймворками
Сейчас есть поддержка PSGI во всех популярных web-фреймворках: Catalyst, CGI::Application, HTTP::Engine, Dancer, Mason, Squatting, Continuity, Maypole, Tatsumaki
Ссылки
Сайт PSGI/Plack
Спецификация PSGI на CPAN
PSGI::FAQ
Plack на CPAN