Perl Hackers Hub

第1回 PSGI/Plack―フレームワークとサーバをつなぐエンジン (2)

この記事を読むのに必要な時間:およそ 4 分

Plack─⁠─PSGIユーティリティ

PSGIのおかげで,フレームワークはCGIやFastCGI,mod_perlといった環境の差異を吸収するためのコードを書く必要はなくなり,PSGIのインタフェースだけを実行すればよくなりました。実際に多くのフレームワークがすでにPSGIをサポートしていますが,さて,そうしたアプリケーションをどうやって動かせばよいのでしょうか。

Apacheなど既存のWebサーバでPSGIアプリケーションを動かすには,CGI,FastCGI,mod_perlなどのインタフェースをPSGIに変換する必要があります。また,PSGIをネイティブで実行できるPerlベースのHTTPサーバもほしいところです。

Plackはそうした要件を満たすためのユーティリティで,リファレンス実装としてのPSGIサーバやそれらへのアダプタ,周辺ライブラリや後述するミドルウェアが含まれています。

plackupコマンド

Plackには非常に高速かつ簡単に起動できるスタンドアロンのPSGIサーバ(HTTP::Server::PSGI)とコマンドラインツールが付属しています。

スタンドアロンPSGIサーバ

CPANからPlackをインストールしたあと,リスト1で記述したHello Worldアプリケーションをhello.psgiというファイルにリネームし,plackupというコマンドを使用して起動してみましょう。

> plackup hello.psgi
HTTP::Server::PSGI: Accepting connections at
http://0:5000/

先ほど記述したアプリケーションがスタンドアロンアプリケーションとして起動しました。ブラウザでhttp://localhost:5000/を開くと「Hello World」と表示されたはずです。

同様にFastCGIでこのアプリケーションを起動するには,

> plackup -s FCGI --listen /tmp/fastcgi.sock hello.psgi

のようにします。こうすると,/tmp/fastcgi.sockをUNIXドメインソケットとしてFastCGIデーモンが起動します。あとはApache,lighttpd,nginxなどでFastCGIに接続するための設定を行えばよいでしょう。--portオプションを利用することでTCP/IPで通信することもできます。

なお,CGIやmod_perlについてはスタンドアロンで起動するのではなく,Webサーバから呼び出される形になるためplackupは利用できませんが,.psgiのパスをWebサーバから設定したり,.cgiファイルから呼び出す,といった形で簡単に再利用できます。

スタックトレースとアクセスログ

plackupにはアプリケーションがエラーを起こしたらそのスタックトレースを表示する機能が含まれています。試しに,

> plackup -e 'sub { die "Foo" }'

としてみましょう。-eオプションはperlと同様,指定されたコードをevalするオプションです。これを実行してブラウザを開くと図3のようなHTMLが表示されます。エラーの起こった個所を,実際のコードを見ながら順に追えて非常に便利です。

図3 スタックトレースの表示

図3 スタックトレースの表示

また,Apacheと同様の形式のアクセスログがターミナルに表示されます。これも開発時にデフォルトで有効になっている機能です。

スタックトレースとアクセスログを無効にするには,-Eオプションでdevelopment以外の値を指定します。

> plackup -E production app.psgi
そのほかのオプション

そのほかにも,アプリケーションが変更されたら自動で再起動する-rオプションなど,便利なオプションが用意されています。詳しくはplackup--helpと実行してください。

Plack::App─⁠─便利なアプリケーション群

Plackに付属しているツールでちょっと便利なのが,Plack::Appに含まれているアプリケーション群です。スタティックファイルの配信,既存CGIスクリプトをPSGI化して実行,といったアプリケーションが含まれていて,plackupツールなどから簡単に利用できます。たとえば,

> plackup -MPlack::App::Directory \
   -e 'Plack::App::Directory->new->to_app'

のようにすると,カレントディレクトリをドキュメントルートとしたスタティックなWebサーバが起動します。

Plackをインストールするだけで,ほかのWebサーバをインストールすることなく利用可能なので,これだけでも開発環境などで便利に利用できます。また,こうしたPlack::Appに含まれるモジュールは,ユーザが開発するアプリケーションに組み込むことも容易にできるようになっています。

PSGIミドルウェア

PSGIアプリケーションはコードリファレンスであり,サーバはHTTPリクエストを$envの形に変換してコードに渡し,アプリケーションは受け取ったハッシュ($env)を利用してリクエストを処理し,レスポンスを配列リファレンスにして返します。このようなシンプルな仕様であることのメリットには,実装が簡単であり,特定のモジュールに依存しないということのほかに,実行時にアプリケーションや環境,レスポンスを(外側から)動的に書き換えるためのプロキシ的なコードを差し込むことが可能である,ということが挙げられます。このしくみを「PSGIミドルウェア」と呼び,図示すると図4のようになります。

図4 PSGIミドルウェア

図4 PSGIミドルウェア

リスト2はHTTPクライアントのIPアドレスをREMOTE_ADDRから取得して表示するシンプルなアプリケーションですが,これをリスト3のようにしてみるとどうでしょう。$appは先ほどと同様のコードですが,$mwでは$envを受け取り,そのREMOTE_ADDRをランダムに2分の1の確率で1.2.3.4に変更して,もとの$appを実行しています。

リスト2 クライアントのIPを表示するPSGIアプリケーション

my $app = sub {
    my $env = shift;
    return [
        200,
        [ "Content-Type", "text/plain" ],
        [ "Hello $env->{REMOTE_ADDR}" ],
    ];
};

リスト3 REMOTE_ADDRを上書きするミドルウェア

my $app = sub {
    my $env = shift;
    return [
        200,
        [ "Content-Type", "text/plain" ],
        [ "Hello $env->{REMOTE_ADDR}" ],
    ];
};

my $mw = sub {
    my $env = shift;
    $env->{REMOTE_ADDR} = '1.2.3.4' if rand(1) > 0.5;
    $app->($env);
};

ブラウザで開くと50%の確率で「Hello 1.2.3.4」と表示され,またその際のターミナルに表示されるアクセスログでも

1.2.3.4 - - [10/Jan/2010 21:05:17] "GET / HTTP/1.1" 200 13 ...

のように1.2.3.4と書き換わっているのがわかります。

実際にはあまり役に立たない例ですが,このように既存のアプリケーションに手を入れることなく,実行の前後にリクエストやレスポンスの中身をフックできるのがわかると思います。

また,この例ではラップされるPSGIアプリケーションをインライン($app)で記述していますが,こうしたミドルウェアはPSGIを実装したすべてのフレームワークで利用できます。Catalystなどのフレームワークでは多くの機能がプラグインやアクションといった拡張として用意されていますが,これらはCatalystでしか利用できませんでした。WebサーバのApacheに用意されている多くのmod_*モジュールも同様です。PSGIの仕様に沿ったミドルウェアでこうした拡張機能を記述すれば,PSGIを利用したサーバ,フレームワークで共有できます。

Plackには多くのミドルウェアが実装され,Plack::Middlewareという名前空間の下にバンドルされています。その使い方については後述します。

著者プロフィール

宮川達彦(みやがわたつひこ)

1977神奈川県生まれ。東京大学理学部卒業後,2000年に(株)オン・ザ・エッヂ(現(株)ライブドア)入社,執行役員Chief Technology Architectとして開発などに携わる。2005年よりシックスアパート(株)に入社,現在は米Six Apart, Ltd.に勤務。ニュースコンテンツの再配信サービス「Bulknews」やフィードアグリゲータ「Plagger」の作者であり,日本を代表するPerlハッカーの一人。カンファレンスでの発表だけでなくイベントも数多く運営するなど,精力的に活動している。個人ブログはhttp://blog.bulknews.net/mt/など。

コメント

コメントの記入