Plack::Middlewareでリクエスト終了後になにがしかのか処理をしたい場合

sub call {
    my ($self, $env) = @_;
    my $t0 = [gettimeofday];
    my $res = $self->app->($env);
    my $ela = Time::HiRes::tv_interval($t0);
};

と書きそうになりますが、これだと $res が CodeRef になるStreaming形式のレスポンスでは正しく処理ができません。 Streaming形式のレスポンスは多くないだろうとか思ってると、Catalystがstreaming形式のレスポンスを返したりするので注意が必要です

そこで Plack::Util::response_cb を使うと楽です

sub call {
    my ($self, $env) = @_;
    my $t0 = [gettimeofday];
    my $res = $self->app->($env);
    Plack::Util::response_cb($res, sub {
        my $res = shift;
        sub {
            my $chunk = shift;
            if ( ! defined $chunk ) {
                my $ela = Time::HiRes::tv_interval($t0);
            }
            return $chunk;
        }
    });
};

リクエスト処理が終わると、$chunk が undefined になるのでそこで、ごにょごにょ処理します。

ただ response_cb はレスポンスのbodyにフィルタをかける用に作られているためか、Content-Length ヘッダが消されてしまいます。レアケースでContent-Typeを消したくない時、またresponse_cbをスキップして処理を高速化(ベンチマーク未実施)したい時は、responseが配列かどうか確認して処理してしまうのが良いでしょう

sub call {
    my ($self, $env) = @_;
    my $t0 = [gettimeofday];
    my $res = $self->app->($env);
    if ( ref($res) && ref($res) eq 'ARRAY' ) {
        my $ela = Time::HiRes::tv_interval($t0);
        return $res;
    }
    Plack::Util::response_cb($res, sub {
        my $res = shift;
        sub {
            my $chunk = shift;
            if ( ! defined $chunk ) {
                my $ela = Time::HiRes::tv_interval($t0);
            }
            return $chunk;
        }
    });
};

以上、Plack::Middleware::AxsLogServerStatus::Liteはこんな実装になってますよという話でした

このブログ記事について

このページは、Masahiro Naganoが2013年2月 4日 11:59に書いたブログ記事です。

ひとつ前のブログ記事は「Procletのオブジェクトインターフェイスでも起動するコマンドを直接書けるようにした」です。

次のブログ記事は「Plack::Middleware::ServerStatus::Lite が IPv6 サポートしました」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

OpenID対応しています OpenIDについて
Powered by Movable Type 4.27-ja