如果我理解正确的话,PSGI应用程序如下:
- 从浏览器获得请求
- 请求是按照
builder
中定义的顺序通过一些中间件的"气泡"。 - 请求到达我的应用
- 我的应用程序产生一些响应
- 此响应再次通过一些中间件起泡
- 最后将响应发送到浏览器
当请求到达我的$app
时,我可以很容易地调试打印所有头(例如cookies)。
问题是:如何调试打印headers
的实际状态,而请求通过许多中间件来我的应用程序,而响应是再次通过中间件出去。
所以,有一个(简化的)app.psgi
,就像下面的:
use strict;
use warnings;
use Plack::Builder;
my $app = sub { ... };
builder {
# <- debug-print the first request headers
# and the last respond headers here
enable "Debug";
# <- debug-print the actual state of request/respond headers here
enable "mid2";
# <- and here
enable "mid3";
# <- and here
$app; # <- and finally here - this is of course EASY
}
这可能不像这样简单,
print STDERR Dumper $dont_know_what->request->headers(); #HTTP::Headers ???
print STDERR Dumper $dont_know_what->respond->headers();
所以添加赏金:);)
一种基本方法是创建一个中间件,在执行包装后的应用程序之前和之后转储报头。然后,在您希望看到您在伪代码中指出的头的每个点启用此中间件。
下面的代码通过在每次启用时构建一个内联中间件来实现这一点。
use Plack::Builder;
use Plack::Request;
use Plack::Response;
sub headers_around {
my $position = shift;
# build and return the headers_around middleware as a closure
return sub {
my $app = shift;
# gets called each request
return sub {
my $env = shift;
my $req = Plack::Request->new($env);
# display headers before next middleware
print STDERR "req headers before $position:n" . $req->headers->as_string . "n=====n";
# execute the next app on the stack
my $res = $app->($env);
my $response = Plack::Response->new(@$res);
# display headers after previous middleware
print STDERR "res headers after $position:n" . $response->headers->as_string . "n=====n";
return $res;
};
};
};
builder {
enable headers_around('Debug');
enable 'Debug';
enable headers_around('Lint');
enable 'Lint';
enable headers_around('StackTrace');
enable 'StackTrace', force => 1;
enable headers_around('App');
mount '/' => builder { sub {
return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello World' ] ];
}}
};
# now build the application enabling regular middleware with our inline middleware
builder {
enable headers_around('Debug');
enable 'Debug';
enable headers_around('Lint');
enable 'Lint';
enable headers_around('StackTrace');
enable 'StackTrace', force => 1;
enable headers_around('App');
mount '/' => builder { sub {
return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello World' ] ];
}}
};
当我用plackup运行它时,我得到以下输出:
$ plackup --app between_middleware.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
req headers before Debug:
Connection: Keep-Alive
Accept: */*
Host: 0:5000
User-Agent: Wget/1.12 (linux-gnu)
=====
req headers before Lint:
Connection: Keep-Alive
Accept: */*
Host: 0:5000
User-Agent: Wget/1.12 (linux-gnu)
=====
req headers before StackTrace:
Connection: Keep-Alive
Accept: */*
Host: 0:5000
User-Agent: Wget/1.12 (linux-gnu)
=====
req headers before App:
Connection: Keep-Alive
Accept: */*
Host: 0:5000
User-Agent: Wget/1.12 (linux-gnu)
=====
res headers after App:
Content-Type: text/plain
=====
res headers after StackTrace:
Content-Type: text/plain
=====
res headers after Lint:
Content-Type: text/plain
=====
res headers after Debug:
Content-Type: text/plain
=====
127.0.0.1 - - [02/Apr/2014:19:37:30 -0700] "GET / HTTP/1.0" 200 11 "-" "Wget/1.12 (linux-gnu)"
显然,你可以把它变成一个实际的中间件,像阿什利的,你可能不得不调整它发送日志消息使用任何设施,你已经在适当的
中间件
package ShowMeTheHeaders;
use parent "Plack::Middleware";
use Plack::Request;
use Plack::Response
require Text::Wrap;
my $_call_back = sub {
my $response = Plack::Response->new(@{+shift});
print "* Response Headers:n",
Text::Wrap::wrap("t", "t", $response->headers->as_string);
return; # Explicit return suggested by docs.
};
sub call {
my $self = shift;
my $request = Plack::Request->new(shift);
print "* Request Headers:n",
Text::Wrap::wrap("t", "t", $request->headers->as_string);
my $response = $self->app->($request);
Plack::Util::response_cb($response, $_call_back);
}
1;
您可以在没有对象化(Plack::Request和Plack::Response)的情况下做到这一点,但是您必须处理报头字段的原始属性和键,而不是完全更令人愉快的->as_string
。参见Plack::Middleware的" response callback "部分。
演示psgi
use warnings;
use strict;
use Plack::Builder;
my $app = sub {
[ 200,
[ "Content-Type" => "text/plain" ],
[ "O HAI, PLAK!" ]
];
};
builder {
enable "+ShowMeTheHeaders";
mount "/" => $app;
};