Perl-программист
0,0
рейтинг
1 июля 2012 в 21:52

Разработка → Mojolicious/PSGI-приложение на виртуальном хостинге

Perl*
О Mojolicious уже написано какое-то количество статей из которых можно получить общие впечатления о этом веб-фреймворке. Читая публикации можно понять, как легко разворачивается приложение, в том числе и PSGI, маштабируется, взаимодействует с веб-серверами и выдерживает высокие нагрузки. Всё это хорошо, конечно, но почему-то нет статьи о том, как запустить приложение на обыкновенном вирутальном хостинге. Хотя, может быть её нет по тому, что это сделать до неприличия просто?

Требования.



Как бы там ни было, но виртуальный хостинг должен удовлетворять некоторые требования.
  • установлен Perl версии 5.10 или выше;
  • разрешено использование cgi-скриптов;
  • поддерживаться mod_rewrite;

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

Что бы запускать PSGI-приложение на хостинге должен быть установлен Plack и поддерживаться mod_perl.

Mojolicious-приложение



Если у вас такового ещё нет, то предлагаю немного развлечься и проверить Хабрахабр на толерантность. Для этого нам понадобится сам Mojolicious, ваше любимое IDE и немного терпения.

Каркас приложения


Первый шаг, это генерации каркаса приложения. Так как мы хотим выбраться за пределы однострочного приложения и положить конец противостоянию Dancer vs Mojolicious, откажемся от Lite-версии:
habra@cynovg-notebook:~$ mojo generate app Habra
  [mkdir] /home/habra/habra/script
  [write] /home/habra/habra/script/habra
  [chmod] habra/script/habra 744
  [mkdir] /home/habra/habra/lib
  [write] /home/habra/habra/lib/Habra.pm
  [mkdir] /home/habra/habra/lib/Habra
  [write] /home/habra/habra/lib/Habra/Example.pm
  [mkdir] /home/habra/habra/t
  [write] /home/habra/habra/t/basic.t
  [mkdir] /home/habra/habra/log
  [mkdir] /home/habra/habra/public
  [write] /home/habra/habra/public/index.html
  [mkdir] /home/habra/habra/templates/layouts
  [write] /home/habra/habra/templates/layouts/default.html.ep
  [mkdir] /home/habra/habra/templates/example
  [write] /home/habra/habra/templates/example/welcome.html.ep

Удаляем директории с примерами, если мешают и приступаем к развлечению.

Проектирование приложения


Что бы приложение было хоть чуть-чуть серьёзнее, чем «Hello, World!», предлагаю использовать поиск Хабрахабры для отработки навыков. А именно, запрашивать у пользователя поисковую строку, отдавать её Хабру, получать ответ и выводить его пользователю.

Начнем с малого, научимся генерировать форму ввода поискового запроса и выводить шаблон-заглушку, как реакцию на получение данных от пользователя. Для этого понадобится маршрут к форме ввода, сам шаблон формы и ответ-заглушка.

Все маршруты у нас хранятся в модуле Habra.pm, расположенном в директории lib, содержимое которого после генерации будет выглядеть следующим образом.
package Habra;
use Mojo::Base 'Mojolicious';

# This method will run once at server start
sub startup {
  my $self = shift;

  # Documentation browser under "/perldoc"
  $self->plugin('PODRenderer');

  # Router
  my $r = $self->routes;

  # Normal route to controller
  $r->get('/')->to('example#welcome');
}

1;

Так как мы занимаемся поиском, то логично назвать наш контроллер Search, а маршруты к нему, соотвественно, search#default и search#result. По умолчанию будем выводить форму ввода:
  $r->route( '/' )->via('get')->to( 'search#default' );

и создадим шаблон для формы ввода, расположив его в /templates/search/deafult.html.ep:
% layout 'default';
% title 'Форма поискового запроса';
<form action='<% url_for %>' method='post'>
    <input type='text' name='q' placeholder='Что будем искать?'>
    <input type='submit' value='Поехали!'>
</form>

Теперь, после того, как удалили все лишнее из модуля Habra.pm и изменили маршрут по умолчанию, наш модуль должен выглядеть следующим образом:
package Habra;
use Mojo::Base 'Mojolicious';

sub startup {
  my $self = shift;
  my $r = $self->routes;
  $r->route( '/' )->via('get')->to( 'search#default' );
}

1;

Проверим, как он работает, запустив из командной строки скрипт из одноименной директории:
morbo script/habra 
Server available at http://127.0.0.1:3000.

Обратившись к нему из браузера по адресу 127.0.0.1:3000 должна быть отображена наша форма ввода, которая, конечно же, приводит к краху приложения как только мы куда-нить собираемся поехать. А происходит это по тому, что у нас нет маршрута к контролу для метода post, который используется для передачи данных из формы ввода. Добавим маршрут в основном модуле и временный шаблон-заглушку в шаблонах, Для этого в основном модуле добавим строчку:
  $r->route( '/' )->via('post')->to( 'search#result' )

и создадим шаблон вывода данных, templates/search/result.html.ep
% layout 'default';
% title 'Результат поиска';

Если мы сейчас проверим, как работает наше приложение, то увидим, что в качестве реакции на наше желание куда-нить поехать, будет пустая страница с заголовком «Результат поиска».

Что бы достигнуть нашей цели, понадобится реализация метода result в ко́нтроле, который бы принимал запрос, отправлял его на хабр и преобразовывал ответ из Хабра в удобную нам форму. Для этого создаем модуль lib/Habra/Search.pm с следующим содержимым:
package Habra::Search;
use Mojo::Base 'Mojolicious::Controller';

sub result
{
    my $self = shift;
    my $str  = $self->param( 'q' );
    my $ua  = Mojo::UserAgent->new;
    my $dom = $ua->get( 'http://habrahabr.ru/search/?q='.$str )->res->dom;
    my $pull = ();
    for my $raw ( $dom->find( 'div[id^="post"]' )->each )
        {
            my $header= $raw->find( 'a[class="post_title"]' )->first;
            push @$pull, {
                title => $header->text,
                url => $header->{href},
                content => $raw->find( 'div[class^="content"]' )->first->text
            };
        }
    $self->render( result => $pull );
}

1;

и дополняем шаблон-заглушку для вывода результата запроса:
% layout 'default';
% title 'Результат поиска';
<ul>
    % for my $row ( @$result ) {
        <li>
            <h2><%= $row->{title} %></h2>
            <p><%= $row->{content} %></p>
            <p>Ссылка на статью: <a href="<%= $row->{url} %>"><%= $row->{url} %></a></p>
        </li>
    %}
</ul>

Если есть какой-то более простой или, на ваш взгляд, более «правильный» способ извлечения данных, то я бы с удовольствием узнал о нём.

Будем считать, это для первого знакомства этого будет достаточно, но основной цели мы на данном этапе мы всё ещё не достигли, так как наше приложение всё ещё находится на локальной машине. Самое время запустить его на виртуальном хостинге.

Публикация приложения



На данном этапе мы имеем хостинг, соотвествующий требованиям и рабочее приложение. Осталось дело за малым, опубликовать его. Ах да, давайте будем считать, что доменное имя у нас mojoex.am.pl, а путь к сайту /home/mojoex.am.pl/www

Для запуска приложения необходимо скачать исходные коды Mojolicious, на пример, с GitHub
git clone https://github.com/kraih/mojo.git

после чего удалить всё лишнее из дистрибутива, оставив только директорию lib, посколько именно там хранятся все модули. Что бы не путаться между модулями приложения и модулями самого Моджолишес, можно переименовать директорию lib на пример, в mojo.

Следующим шагом немного модифицируем скрипт, запускающий приложение, добавив в его заголовок указатель на директории с модулями Моджолишис и самого приложения и переименуем его в habra.cgi
use lib ( '/home/mojoex.am.pl/mojo' );
use lib ( '/home/mojoex.am.pl/lib' );

Очередным шагом надо выложить модули Моджолишес за пределамы сайта, по пути /home/mojoex.am.pl/mojo. По этому же пути выложить модули приложения и шаблоны, /home/mojoex.am.pl/lib и /home/mojoex.am.pl/templates, соотвествтенно. Так же создадим директорию для логов, /home/mojoex.am.pl/log. А вот скрипт, который стартует приложение надо разместить в директории /home/mojoex.am.pl/www/cgi-bin, с правом на исполнение.

Последним шагом будет немного магии с mod_rewrite. Необходимо создать правила, для этого создадим файл .htaccess, который должен раполагаться в директории /home/mojoex.am.pl/www, с следующим содержимым:
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /cgi-bin/habra.cgi/$1 [L]
RewriteRule ^$ /cgi-bin/habra.cgi [L]


frenzytechnix Подсказывает, что если на хостинге установлен mod_perl, то мы можем запускать PSGI-приложение. Для этого необходимо указать в .htaccess следующее:
<Perl>
    $ENV{PLACK_ENV} = 'production';
    $ENV{MOJO_HOME} = '/home/mojoex.am.pl';
    $ENV{MOJO_TEMPLATE_CACHE} = 0;
    $ENV{PERL5LIB} .= '/home/mojoex.am.pl/lib;/home/mojoex.am.pl/mojo'
</Perl>
    SetHandler perl-script
    PerlHandler Plack::Handler::Apache2
    PerlSetVar psgi_app /home/mojoex.am.pl/www/cgi-bin/habra


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

Резюме



В итоге структура хостинга должна выглядеть схожим образом:
/home/mojoex.am.pl/                             # корень сайта
/home/mojoex.am.pl/mojo/                        # директория с модулями Mojolicious
/home/mojoex.am.pl/lib/                         # директория с модулями приложения
/home/mojoex.am.pl/log/                         # директория с логами работы приложения
/home/mojoex.am.pl/www/.htaccess                # файл с правилами для mode_rewrite
/home/mojoex.am.pl/www/cgi-bin/habra.cgi        # скрипт, запускающий приложение

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

Если кому-то фрагмент кода может показаться зубодробительным, либо есть какие-то непонятные моменты, замечания или предложения, оставляйте комментариях.
Cyrill Novgorodcev @cynovg
карма
2,0
рейтинг 0,0
Perl-программист
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (12)

  • +1
    Давно уже хочу попробовать поиграться с perl и mojolicious(кстати добавьте в теги).
    Еще помню как читал тут на хабре статью о Frodio что он сделан на данном фреймворке, но руки все никак не доходят. А на этот раз думаю наконец попробую.
    Из вашей статьи мне не понравилось только что используется Apache. Я с ним уже давно дел не имею и не хочу даже связываться. Ну я понял какнешно что Apache тут в связи с тем что статья нацелена на деплой на обычных хостингах, но мне это не подходит. Может кто посоветует как сейчас лучше деплоить Perl-приложение через nginx например?
    • –1
      Наезды на апач непонятны, ну да ладно — это сейчас модно.
      Деплоить mojo приложения наверно надо через hypnotoad, как и описано в документации, и подключать nginx как фронтэнд — поддержка тоже есть в hypnotoad.

      • 0
        Спасибо, а я еще нашел Starman — про него что скажете?
        При чем тут nginx это модно? Модно сейчас вообще ничего не админить а хоститься на всяких Heroku.
        Но apache я сменил на nginx по причине того что индеец слишком много памяти кушал. А потом постепенно я вообще даже и считаться с ним перестал. Я же не собирался доказывать что один круче другого. Я написал «мне это не подходит».
        • +1
          Starman — быстрее. Но он не умеет (и скорее всего не будет) вебсокеты.
    • 0
      У меня не было необходимости использовать что-то отличное от обычного хостинга и Апача, по этому не могу сказать.
    • 0
      Ниже в комментарии подсказали, что надо указать в .htaccess для запуска PSGI-приложения. Ну, и в тело стати добавил, за одно.
  • 0
    Спасибо за статью! Я уже год использую данный фреймворк, изучил его вдоль и поперек. Однозначный тренд! Perl возрождается благодаря таким вещам! Спасибо всем, кто его разрабатывает и использует!
    • 0
      Тоже чуть больше года использую Mojolicious, доволен невероятно, использую в коммерческом проекте.
  • 0
    Отличный пример! Несколько режет глаз строка:

    my $pull = ();

    Так как обычно пишу или

    my @pull = ();

    или

    my $pull = [];

    Ну это дело привычки =)
    • 0
      По-моему, не только привычки:
      my $c = ();
      my $h = [];
      say "Defined C" if defined $c;
      say "Defined H" if defined $h;
      

      Результат:
      perl test.pl 
      Defined H
      
      • 0
        Согласен. Подзабыл про такую особенность.
  • 0
    Если на хостинге с апачем поддерживается mod_perl, то лучше разворачивать Mojolicious-приложение как PSGI-приложение через Plack. Возни немного, а скорость работы будет заметно выше.

    Вот пример конфига, адаптированный под приложение из статьи.
    <Perl>
        $ENV{PLACK_ENV} = 'production';
        $ENV{MOJO_HOME} = '/home/mojoex.am.pl';
        $ENV{MOJO_TEMPLATE_CACHE} = 0;
        $ENV{PERL5LIB} .= '/home/mojoex.am.pl/lib;/home/mojoex.am.pl/mojo'
    </Perl>
    <Location "/">
        SetHandler perl-script
        PerlHandler Plack::Handler::Apache2
        PerlSetVar psgi_app /home/mojoex.am.pl/script/habra
    </Location>
    

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.