Perl Hackers Hub

第41回 Plack::Middleware再入門(2)

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

前回の(1)こちらから。

さまざまなPlack::Middleware

Plack::Middlewareの3パターンについて具体的なモジュールを見ながら理解を深めたところで,CPANにアップロードされているPlack::Middlewareの中から,筆者が注目しているものをピックアップして紹介したいと思います。

なお,本節で登場するenable関数は,Plack::Middlewareをロードして有効にするもので,第1引数にミドルウェアの名前,第2引数以降にオプションを取ります。

開発を捗らせるPlack::Middleware

プロダクション環境では必要ありませんが,開発環境で使うと捗るPlack::Middlewareがあります。

DebugLogging─⁠─コンソールにデバッグ情報を出力する

Plack::Middleware::DebugLoggingは,リクエストパスやHTTPヘッダといったリクエストとレスポンスに関連するパラメータをコンソールに表示してくれます。

enable "DebugLogging";

たとえば,Content-type: application/jsonでJSONをリクエストすると,デコードしたものがダンプされるので開発が捗ります。

$ curl -X POST -H "Content-type: application/json" -d '{"user":123}' http://127.0.0.1:5000/?foo=bar

上記のようなリクエストを投げると,次のようなデバッグ出力を得ることができます。

"POST" request for "/" from "127.0.0.1"
Request Headers:
.-----------------+-----------------------------------.
| Header Name     | Value                             |
+-----------------+-----------------------------------+
| Accept          | */*                               |
| Host            | 127.0.0.1:5000                    |
| Content-Length  | 12                                |
| Content-Type    | application/json                  |
'-----------------+-----------------------------------'

Query Parameters are:
.-----------------------+-----------------------------.
| Parameter             | Value                       |
+-----------------------+-----------------------------+
| foo                   | bar                         |
'-----------------------+-----------------------------'

application/json encoded body parameters are:
{
  user => 123
}
StackTrace::LinkedSource─⁠─スタックトレースからソースをブラウザで表示する

Plackの開発環境では,エラーが発生した場合,HTMLで見やすく整形されたスタックトレースが表示されます。Plack::Middleware::StackTrace::LinkedSourceは,そのスタックトレースに含まれるモジュールのパスからソースコードをブラウザで直接参照できるようにしてくれます図2)⁠

enable "StackTrace::LinkedSource",
    lib => ['/your/app/lib', @INC];

図2 StackTrace::LinkedSourceによるソースコードの表示

図2 StackTrace::LinkedSourceによるソースコードの表示

ローカルの実行環境ならソースコードを参照するのも難しくないと思いますが,デザイナーの作業環境やQAQuality Assuarance品質保証)環境といった別環境でエラーが起きた場合に,ブラウザのスタックトレースからそのままコードが追えるので便利です。

HTTPヘッダを扱うPlack::Middleware

WebアプリケーションでHTTPヘッダを扱う場面はたくさんあります。そうしたものの中には,アプリケーションでその都度扱うよりも,Plack::Middlewareで一括して面倒を見てもらったほうが楽なものがあります。

ETag─⁠─ETagヘッダを自動で付与する

Plack::Middleware::ETagは,コンテンツの変更を検知するための一意の識別子であるETagヘッダをレスポンスに付与します。

enable "ETag";

アプリケーションで静的ファイルを配信している場合は,デフォルトでinode(ファイルの管理番号)⁠mtime(最終更新日時)⁠size(ファイルサイズ)の情報から値を生成します。動的コンテンツの場合は,コンテンツのダイジェストハッシュを値とします。モジュールの利用者は通常それらを意識することなく,上記の1行を書くだけで対応できます。

ConditionalGET─⁠─ステータスコード304に対応する

Plack::Middleware::ConditionalGETは,リクエストにIf-None-MatchヘッダやIf-Modified-Sinceヘッダがある場合に,レスポンスのETagヘッダやLast-Modifiedヘッダと比較して同じ値の場合は,更新がない旨を表すステータスコード304(Not Modified)を自動的に返却します。ステータスコード304はコンテンツ自体の送信が不要なので,転送量を削減できます。先に紹介したPlack::Middleware::ETagとセットで利用すると便利です。

enable "ConditionalGET";
CrossOrigin─⁠─CORSに対応する

Plack::Middleware::CrossOriginは,クロスドメインでXMLHttpRequestを行いたい場合などに必要なCORSCross-Origin Resource Sharingに対応できます。

enable "CrossOrigin",
    origins => '*',
    methods => ["GET", "POST"],
    max_age => 60*60*24*30;

CORSに対応するヘッダは,一般的にApacheやnginxなどで設定することが多いかもしれませんが,たとえばリクエストパスに応じて処理をするというような込み入った条件のある場面では,Plack::Middlewareで行ったほうが簡単かもしれません。

プロダクションに常時投入したいPlack::Middleware

ここでは,プロダクションに常時投入したいPlack::Middlewareを紹介します。

次に紹介する2つのPlack::Middlewareは,プロダクション環境に素直に投入すると処理性能がいくらか劣化します。とはいえ,取得できる情報はいざというときに重要なものですので,できれば常時運用で投入しておきたいところです。常時運用で投入するための工夫としては,たとえば,特定サーバのみで有効になるようにしたり,特定プロセスでのみ有効にしたり,特定のエンドポイントでのみ有効にするといったアプローチが考えられます。サーバ構成の状況を見ながら対応するとよいでしょう。

MemoryUsage─⁠─メモリの使用量を見る

Plack::Middleware::MemoryUsageは,ロードされたモジュールごとのメモリ使用量を計測できます。

enable "MemoryUsage",
    callback => sub {
        my ($env, $res, $before, $after, $diff) = @_;
        my $worst_count = 3;
        for my $pkg (sort {
                $diff->{$b} <=> $diff->{$a}
            } keys %$diff) {
            warn sprintf("%-32s %8d = %8d - %8d[KB]\n",
                         $pkg,
                         $diff->{$pkg}/1024,
                         $after->{$pkg}/1024,
                         $before->{$pkg}/1024,
                        );
            last if --$worst_count <= 0;
        }
    };

出力内容はcallbackオプションにコードリファレンスを自分で書く必要がありますが,上記のようにSYNOPSISをそのままコピーして動かせます。出力例は次のようになります。

B::PVOP             0 =       5 -       4[KB]
B::PVIV             0 =       2 -       1[KB]
B::IV               0 =      10 -      10[KB]

IO::Socket::INET    0 =     137 -     137[KB]
Apache2::Status     0 =      18 -      18[KB]
Symbol              0 =      19 -      19[KB]
Profiler::NYTProf─⁠─プロファイリングを取得する

Plack::Middleware::Profiler::NYTProfは,PerlのデファクトスタンダードプロファイラであるところのDevel::NYTProfをPlackアプリケーションで利用するためのミドルウェアです。

enable "Profiler::NYTProf",
    enable_profile => sub { $$ % 2 == 0 },
    env_nytprof => 'start=no:addpid=0',
    enable_reporting => 0;

prefork型のアプリケーションにおいて,親プロセスのプロファイリングを取得しないで,子プロセスだけのプロファイリングを取得できます。また,プロファイルの有効無効や結果ファイル名を動的にカスタマイズすることもできます。

著者プロフィール

岡林大(おかばやしだい)

主にPerlでサーバサイドを書く人ですが,たまにJavaScriptでフロントも書きます。自由でロックなWebが大好き。お仕事以外ではラーメンを食べるかOSSに貢献する#yapcramenの人。

GitHub:bayashi

コメント

コメントの記入