本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはbayashiこと岡林大さんで、
本稿のサンプルコードは、
今も熱いPlack::Middleware
PSGIは
PSGI/
今回は、
Plack::Middlewareとは
Plack::Middlewareは、

何も処理をしないシンプルなPlack::Middlewareの実装例は、
package Plack::Middleware::Foo;
use parent qw( Plack::Middleware );
sub call {
my ($self, $env) = @_;
# 1. ミドルウェアの処理
my $res = $self->app->($env); # アプリケーションの処理
# 2. ミドルウェアの処理
return $res;
}
リクエストごとに呼ばれるcall
メソッドで$env
を受け取り、$res
$self->app
がラップされるアプリケーションの処理で、
つまり、
- アプリケーションの処理の前に仕事をするもの
- アプリケーションの処理のあとに仕事をするもの
- アプリケーションの処理の前後両方で仕事をするもの
という3パターンがあります。
以降ではこの3パターンについて、
PSGIアプリケーションの入り口で処理
まずは、REMOTE_
HTTP_
SERVER_
ソースコードは次のようになっています
sub call {
my $self = shift;
my $env = shift;
$env->{HTTPS} = $env->{'HTTP_X_FORWARDED_HTTPS'}
if $env->{'HTTP_X_FORWARDED_HTTPS'};
$env->{HTTPS} = 'ON'
if $env->{'HTTP_X_FORWARDED_PROTO'}
&& $env->{'HTTP_X_FORWARDED_PROTO'} eq 'https';
$env->{'psgi.url_scheme'} = 'https'
if $env->{HTTPS} && uc $env->{HTTPS} eq 'ON';
(省略)
$self->app->($env);
}
Plack::Middleware::ReverseProxyによってアプリケーションではリバースプロキシによる環境変数の書き換えを意識せずにコーディングできます。もしこのミドルウェアがなければ、
このように、
PSGIアプリケーションの出口で処理
続いては、
次のコードでは、$self->app
のあとにContent-Typeを確認しつつ、
sub call {
my $self = shift;
my $res = $self->app->(@_);
$self->response_cb($res, sub {
my $res = shift;
my $h = Plack::Util::headers($res->[1]);
return unless $h->get('Content-Type');
if ($h->get('Content-Type') =~ m!^text/!) {
return sub {
my $chunk = shift;
return unless defined $chunk;
local $_ = $chunk;
$self->filter->();
return $_;
};
}
});
}
$self->response_
やPlack::Util
に属する関数が登場していますが、$self->app
のあとに処理をしているという構造に注目しておきましょう。
PSGIアプリケーションの入り口と出口で処理
さらに、
次のコードでは、$self->app
の前に時間を取っておき、
sub call {
my($self, $env) = @_;
my $start = [ Time::HiRes::gettimeofday ];
my $res = $self->app->($env);
my $header = $self->header_name || 'X-Runtime';
$self->response_cb($res, sub {
my $res = shift;
my $req_time
= sprintf '%.6f',
Time::HiRes::tv_interval($start);
Plack::Util::header_set(
$res->[1],
$header,
$req_time
);
});
}
このような処理は、$self->app
をラップしているという設計であればこそです。もしアプリケーションの前後に処理が分離した設計だったら、
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.133
2023年2月24日発売
B5判/176ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13370-2
- 特集1
識者がたどり着いた最適解
TypeScript最新活用
リンタ、バンドラ、ランタイム、エッジ - 特集2
コミッター直伝!
速習Ruby 3.2
Wasm対応、ReDoS対策、性能改善 - 特集3
Tailwind CSS実践入門
まず作ってから、あとで共通化する