ziguzagu.org

CGI::Application::Dispatchまとめ

ここ1ヶ月ほど(ながいなぁ…)、ちまちまと勉強してきたCGI::Application::Dispatchについて、使い方もこなれて来たので、ここいらでひとまとめです。

何するモジュール?

この勉強中エントリーの1回目でも書きましたが、CGI::Applicationを利用したアプリで必要になるインスタンスCGIは作らずに、URI(PATH_INFO)から実行するモジュールとRunモードを決定する、というモジュールです。newしてrunするだけのインスタンスCGIなんか毎回書きたくないよ、というのがモジュール作者さんの意図のようです(PODにもあります)。

URIはこうなる

CGI::Application::Dispatchを使った場合のURIは、

/どこか/モジュール名/Runモード               # mod_perl使う
/どこか/dispatch.cgi/モジュール名/Runモード  # mod_perl使わない

となります。

CGI::Applicationを継承したMyApp::Indexというモジュールを作った場合、それを実行するためのURIを比較すると以下のようになります。

通常のCGI::Application
http://example.com/index.cgi
http://example.com/index.cgi?rm=mode1
CGI::Application::Dispatch(mod_perlなし)
http://example.com/dispatch.cgi/index/
http://example.com/dispatch.cgi/index/mode1
CGI::Application::Dispatch(mod_perlあり)
http://example.com/app/index/
http://example.com/app/index/mode1

通常のCGI::Applicationのみを使った場合、実行するモジュールごとにインスタンスCGIを追加する必要があります。それが、mod_perlなしのCGI版の場合は1つのCGIのみ、mod_perlを利用してApacheのハンドラとしてDispatchを利用する場合はCGIは必要ありません。

dispatch.cgiの中身

単純なdispatch.cgiの中身は以下のようになります。

#!/usr/bin/perl
use lib qw(/path/to/mylib);
use CGI::Application::Dispatch;
CGI::Application::Dispatch->dispatch(
    PREFIX  => 'MyApp',
    DEFAULT => 'Index',
);

この設定だけでパッケージ名が「MyApp::**」なモジュールすべてが実行可能です。DEFAULTで指定したモジュールは、その名のとおりで、

http://example.com/dispatch.cgi http://example.com/dispatch.cgi/

というモジュール指定のないURIでアクセスされたときに実行するモジュールを指定します。

DispatchテーブルでURl/モジュールマッピング

実際にCGI::Applicationを使っていると、MyApp::Hoge::Fugaというような深い名前空間の階層を持つモジュールや、単純にパッケージ名が長いモジュールが出てくることががあります。こういったときにはTABLEを使って、URIとモジュール名をマップさせます。

#!/usr/bin/perl
use lib qw(/path/to/mylib);
use CGI::Application::Dispatch;
CGI::Application::Dispatch->dispatch(
    PREFIX  => 'MyApp',
    DEFAULT => 'index',
    TABLE   => {
        index => 'Index',
        fuga  => 'Hoge::Fuga',
        bar   => 'Hoge::Foo::Bar',
    },
);

このようにした場合のURIは、

http://example.com/dispatch.cgi/index/  => MyApp::Index
http://example.com/dispatch.cgi/fuga/   => MyApp::Hoge::Fuga
http://example.com/dispatch.cgi/bar/    => MyApp::Hoge::Foo::Bar

となります。TABLEハッシュのキーがURIのモジュール名部分になります。便宜上「モジュール名」としていますが、実際にはただのハッシュのキーなので何でも設定可能です。また、TABLEを指定した場合は、DEFAULTの値は実際のモジュール名ではなくハッシュのキーに指定した値で指定します。

MultiViewsを使った拡張子のないURI

良いURI設計の条件として「技術を丸出しにしない」ということがあるそうです(参考)。ここでいう「技術」とは、拡張子.cgiがURIに含まれることで、サーバー側の実装技術が(実際にCGIとして機能しているかどうかは別に)URIに現れてしまっていることです。

拡張子をURIから取り除く方法としては、mod_rewriteを使うのが一般的ですが、今回の勉強中にApacheのMultiViewsオプションでも実現できることを知ったのでそちらを紹介します。(海賊たろさんに感謝)。

dispatch.cgiが設置されているディレクトリのhtaccessまたは、httpd.confに以下を追加します。

AddHandler cgi-script .cgi
Options +MultiViews +ExecCGI
MultiviewsMatch Handlers        # これがミソ

設定はこれだけで、これまで、

http://example.com/dispatch.cgi/index/mode2

としてきたURIを、

http://example.com/dispatch/index/mode2

というURIでアクセスできるようになります。かっこいい。このミソポイントの内容にについてはこちらを参照

(Dispatch自体には直接関係ありませんが…)。

「HTML内のURI参照は相対パス派」の人向け

これまでCGI::Applicationを、

  1. PATH_INFO未使用
  2. tmpl_path()未使用でインスタンスCGIとテンプレートは同じ階層
  3. HTML内のURI参照は相対パス

という感じで使ってきた人にとっては、Dispatchモジュールはちょっとてこずると思います(自分がそうでした…)。その原因はこちらのエントリーでも書きましたが、すべてのURIがPATH_INFOを使って、

/dispatch.cgi/モジュール名/Runモード

で表され、同じ階層のURIになるためです。インスタンスCGIっていうものが無いので、最初のうちはテンプレートをどこにおいたらいいんだろう???と迷います。これに関しては、かぜぶろさんの方法が激しく参考になります。DispatchテーブルとMultiViewsのサンプルもこのレイアウトを頂いています。

参考とか

過去の関連エントリー

おしまい。