Mojolicious



2013年 5月 21

Mojoliciousのバージョンあげたら動かなくなった。

Mojolicious::Commandsの start メソッドが無くなった

$ENV{MOJO_APP} ||= 'MyApp';
Mojolicious::Commands->start;

エラーになる

Couldn't load application from file "./myapp": Can't locate object method "start" via package "Mojolicious::Commands" at ./myapp line 34.

現在は

Mojolicious::Commands->start_app('MyApp');

$ENV{MOJO_APP}が無くなった

詳細はこのエントリに

最近のMojoliciousのバージョンに関して – kinjou_jのメモログ


Filed under: Mojolicious

Trackback Uri






2013年 5月 5

問題点

この問題は Mojoliciousでhttps(SSL)専用ページとhttp専用ページの振り分けをroutesのbridgeを使って行うを実装した時に起こる問題です。

件のエントリーの実装でもスタンドアロンのサーバで公開する場合には問題にならないのですが、Nginx等のリバースプロクシの後ろにアプリケーションサーバを置いて運用する場合に問題が起きます。

通常、webサーバであるNginxとクライアントの間ではSSL通信を行い、バックエンドのアプリケーションサーバ(Starman等)とNginxの間では通常のhttpで通信すると思います。

           SSL通信
クライアント   ---   Nginx
                     |     http通信
                   Starman

この場合だと、件のエントリーの

  # SSL onry routes
  my $ssl_rotes = $routes->bridge->to(
    cb => sub{
      my $self = shift;
 
      my $req = $self->req;
      return 1 if $req->is_secure;
      
      $self->redirect_to($req->url->to_abs->scheme('https'));
      return;
    }
  );

ようにschemeで判定してhttps~にリダイレクトする場合、Nginxとアプリケーションは常にhttpで通信しているのでリダイレクトが無限ループしてしまいます。

Nginxとアプリケーション間をSSLにすればよいのですが、(アプリケーション側の)ポートを開けたり指定しなくてはならなくなったりと色々面倒なことになりそうです…。

対策

Nginxの設定でリダイレクトを使うか、SSLの場合はリンクをhttpsで指定するかしか無さそう。

例えばstartupの中で下記のようなhelperを定義して、

  # helper method
  $self->helper(
    url_for_http => sub {
      my $self = shift;      
      my $url = $self->url_for(@_)->to_abs->scheme('http');
      return $url;
    }
  );
  $self->helper(
    url_for_https => sub {
      my $self = shift;      
      my $url = $self->url_for(@_)->to_abs->scheme('https');
      return $url;
    }
  );

templateで

<%= link_to url_for_http('/') => begin %>httpを強要<% end %>
<%= link_to url_for_https('/ssl_onry') => begin %>セキュアなページへのリンク<% end %>

のように使うしか無いのかな。


Filed under: Mojolicious

Trackback Uri






2013年 4月 29

mojolicious

このエントリーには問題点があります(2013/5/5追記)

webアプリを作る上でセキュアな通信を強要するページとそうではないページを振り分けるにはどうすればいいのか悩んでいたのだけど、ルーターでリダイレクトさせる方法にしてみた。

全てのページをSSLでアクセスされても速度的にとか負荷的に困るので、ある決まったrouteのみSSLでアクセスして、メインのコンテンツは通常のhttp通信(非SSL)にredirectする仕様。

必ずhttpsでアクセスするルート
  • /login
  • /join
必ずhttpでアクセスするルート
  • /
  • /entry/1
  • /entry/2
  • /entry/….
httpでもhttpsでもいいルート
  • /mypage
  • /favorite/list/1

例ではログインページや登録ページではセキュアな通信をして、トップページとエントリーページは普通のhttpで通信する。httpsでもhttpでもどちらでもいいページは最後の Any routes の所で振り分けられる。

sub startup {
  $self = shift;
....

  # Routes
  my $routes = $self->routes;

  # SSL onry routes
  my $ssl_rotes = $routes->bridge->to(
    cb => sub{
      my $self = shift;

      my $req = $self->req;
      return 1 if $req->is_secure;
      
      $self->redirect_to($req->url->to_abs->scheme('https'));
      return;
    }
  );
  # スッキリ書くならこんな感じ?
  # my $ssl_rotes = $routes->bridge->to(
  #   cb => sub{
  #     return 1 if $_[0]->req->is_secure;      
  #     $_[0]->redirect_to($_[0]->req->url->to_abs->scheme('https'));
  #     return;
  #   }
  # );
  # Not SSL routes
  my $not_ssl_routes = $routes->bridge->to(
    cb => sub{
      my $self = shift;
      
      my $url = $self->req->url;
      return 1 if $url->base->scheme eq 'http';
      
      $self->redirect_to($url->to_abs->scheme('http'));
      return;
    }
  );

  # SSL onry route
  $ssl_rotes->route('/login')->to('login#index');
  $ssl_rotes->route('/join')->to('join#index');

  # not SSL routes
  $not_ssl_routes->route('/')->to('top#index');
  $not_ssl_routes->route('/entry/:id', id => qr/\d+/)->to('entry#index', id => 1 );

  # Any Routes
  $routes->route('/:controller')->to(action => 'index');
  $routes->route('/:controller/:action')->to();
  $routes->route('/:controller/:action/:id')->to();
}

考えついたのはこんな感じのコードだけど、もっといい方法があるかもしれません。知っている方いたら教えて下さい!


Filed under: Mojolicious

Trackback Uri






2011年 11月 28

MojoliciousアプリケーションをCGIで動かす時に、スタイルシートや外部JavaScriptファイル、画像など静的ファイルの扱いには注意が必要になる。

これはテンプレートでタグヘルパーを使った時、例えば

    <%= stylesheet '/css/style.css' %>

とスタイルシートを読み込んだつもりだけど、これはスタイルシートを読み込むCGIを実行するのと同じ(スタイルシートのURLにリダイレクト処理するCGIとして実行される)
静的ファイルを呼び出す回数分のCGIが実行されることになるので、パフォーマンスも悪くなることは当然ながら、データベースの接続処理をstartup内でしていたりすると実行回数分の接続を行う事となる。

以前speedyCGIとしてMojoliciousアプリケーションを動作させていた時に、MySQLの最大同時接続数が異常になってMySQLサーバがダウンした事もある。

MojoliciousでCSSなどの静的ファイルを利用する – サンプルコードによるPerl入門

 ローカル環境で試験をするときは、組み込みのWebサーバーがCSSなどの静的ファイルをディスパッチしてくれるので、パフォーマンスの問題は起こりません。一方さくらのレンタルサーバーではCGIというプロトコルを利用してWebアプリケーションを起動しています。CGIというプロトコルはひとつのアクセスに対してひとつのプロセスを立ち上げます。プロセスの起動という処理はとても時間がかかるので、静的ファイルをCGIでディスパッチするとパフォーマンスの劣化が顕著に見られることになります。

リンク先にあるように、組み込みのwebサーバやその他のプリフォークサーバ(starman等)ならば問題ないのかもしれない。まぁ、それ自体がwebサーバとして動作するものなので当然といえば当然か。

CGIとして動作させる場合の解決策としてmod_rewriteの利用が提唱されている。.httaccess(またはhttpd.conf)でApacheが静的ファイルは静的ファイルとして処理するようにmod_rewriteルールを設定する。

もう一つ解決する方法としては、タグヘルパーを使わずに

    <link href="/css/style.css" media="screen" rel="stylesheet" type="text/css" />

などと直接タグを書いてしまう方法。これはデプロイするときにディレクトリ構成が変わったりすると後々面倒(テンプレートをすべて修正する必要があるとか)なので、推奨される方法ではないのかもしれないけれど。

MojoliciousをCGI動作させていてパフォーマンスがイマイチだな・・・と思っているなら調べてみるといいかもしれない。

App.pmとかのstartup()内に

sub startup {
    warn 'warn CGI run.';
    ....
}

等としてアプルケーションを実行するとapacheのエラーログに記録されるので1度の実行で複数行のログが残っていたらその行数分アプリケーションが実行されていることになる。

Apacheでデプロイする様々な方法

Apache deployment – GitHub
Apache/CGI にmod_rewriteの設定が記述されている。その中の Pretty “Web 2.0” URLs という項目は参考になる。


Filed under: Mojolicious

Trackback Uri






2011年 10月 15

configファイルの読み込み

設定ファイルを読み込む / Mojoliciousリファレンス – サンプルコードによるPerl入門

 設定(コンフィグ)ファイルを読み込むにはMojolicious::Plugin::Configを利用します。

というように、Mojoliciousアプリで設定ファイルを使う事ができる。例えば etc/MyApp.conf を読み込むには以下のような感じ。 stash_keyはオプションで設定できる(デフォルトはconfig?)

etc/MyApp.conf

{
    # MyApp config
    
    # サービス名
    SARVICE_NAME => 'hogehoge',

    # 配列のリファレンス等
    CATEGORY => [0,1,2,3,4],
}

MyApp.pm

package MyApp;

sub startup {
    my $self = shift;

    # コンフィグファイル読み込み
    my $config = $self->plugin('config', { file => 'etc/MyApp.conf', stash_key => 'conf' });
    ....
}

読み込みはリンク先に詳しく書かれている。

configで設定された値を使う

コントローラーとかで使う

sub index {
    my $self = shift;
    
    #my $config = $self->stash('conf');
    my $config = $self->config;
    my $service_name = $config->{SARVICE_NAME};
    # or 
    my $service_name = $self->config('SARVICE_NAME');
    ....
}

テンプレートで使う

    <%= stash('conf')->{SARVICE_NAME} %>
    <%= config->{SARVICE_NAME} %>
    <%= config('SARVICE_NAME') %>

オブジェクト指向的には config()で取得したほうがいいのかな?

テンプレートで使うには

<%= config 'SARVICE_NAME' %>

がタイプが一番少ないようだ。


Filed under: Mojolicious

Trackback Uri