昨天我们看到一个非常简单有效的使用中间件组件的例子。这次我们加入一个基本的 HTTP 的功能 JSONP.
JSONP (JSON-Padding) 是一个非官方的协议,它允许在服务器端使用 JSON 给来给客户端的 javascript callback 进行访问。这可以跨域通过基本 JSON 来包含访问的 HTML script tags 的内容
Middleware::JSONP
假定你的 Web 应用返回 JSON 的编码数据,Content-Type 是 application/json。然后 PSGI 的应用:
use JSON;
my $app = sub {
my $env = shift;
if ($env->{PATH_INFO} eq '/whatever.json') {
my $body = JSON::encode_json({
hello => 'world',
});
return [ 200, ['Content-Type', 'application/json'], [ $body ] ];
}
return [ 404, ['Content-Type', 'text/html'], ['Not Found']];
};加入 JSONP 的支持非常简单,只要使用 Middleware::JSONP:
use Plack::Builder;
builder {
enable "JSONP";
$app;
};他只是一行就完成这个功能。这个中间件检查 response 的内容为 application/json and。如果请求的是 "/whatever.json" 连接后返回标准的 JSON ,但请求 "/whatever.json?callback=myCallback" 会返回
myCallback({"hello":"world"});和 Content-Type text/javascript. Content-Length 是会自动的输出的。
框架中怎么应用
JSONP 除了支持JSON, 能完成大多数框架做的相当琐碎的事,因为 Middleware::JSONP 是放在 Plack 的中间件那层,所以没有多少复杂的东西。
所以, JSONP 中间件应该能工作在任何 Web 框架的 JSON 的输出上,象 Catalyst:
package MyApp::View::JSON;
use base qw( Catalyst::View::JSON );
package MyApp::Controller::Foo;
sub hello : Local {
my($self, $c) = @_;
$c->stash->{message} = 'Hello World!';
$c->forward('MyApp::View::JSON');
}如果使用了 Catalyst::Engine::PSGI 和 Plack::Builder 你要支持 JSONP 的支持控制,如下
use MyApp;
MyApp->setup_engine('PSGI');
my $app = sub { MyApp->run(@_) };
use Plack::Builder;
builder {
enable "JSONP";
$app;
};很意外,Catalyst::View::JSON 是我写的模块,默认支持 JSONP 回调的配置,但是有不止一种方法来做到这一点!
这是译文,原文地址:http://advent.plackperl.org/2009/12/day-16-adding-jsonp-support-to-your-app.html