扶凯

取势 明道 优术

作者为 扶 凯 发表

Hello World! 但其它的啦

看我们前几个章节的例子中,基本上都只是最简单的例子,象下面这个这么简单.

my $app = sub {
    return [ 200, [], [ "Hello World" ] ];
};

如果是更加复杂的例子啦,因为真实的环境一定更加复杂,象很多个应用在一台 web 服务器上,一起为用户服务,各自都有自己的 Web 应用框架,我们以前使用 Apache 就需要使用象 mod_alias 之类的法宝才能搞得定.PSGI 中的应用要怎么办啦?

 

Plack::App::URLMap

Plack::App::URLMap 可以让你给你写的应用整合到看起来一个应用中,然后别名(路径)来到达不同的 url. 这种方式来调度不同的请求到多个不同应用上面去.就象我们平时配置的 Apache 的 alias 一样的调度.

my $app1 = sub {
    return [ 200, [], [ "Hello John" ] ];
};

my $app2 = sub {
    return [ 200, [], [ "Hello Bob" ] ];
};

你现在有二个这样的应用,其中一个是打印 John ,另一个打印 Bob.如果你想使用这二个应用,在同一个服务器上,你可以通过 Plack::App::URLMap 这个模块来实现.你可以这样来做:

use Plack::App::URLMap;
my $app = Plack::App::URLMap->new;
$app->mount("/john" => $app1);
$app->mount("/bob" => $app2);

这就是你想要的功能吧,你的应用现在会给所有路径为 /john 的请求调用 $app1 来响应 John ,对 /bob 的路径会调用 $app2 来响应 Bob .如果是没有映射的路径,象 root 的路径 "/" 这时就会响应 404.
在这个环境变量中例如 PATH_INFO 和 SCRIPT_NAME 是自动的调整的,就象你的应用是使用的 Apache 的 mod_alias 和 CGI 的脚本一样.你的应用框架需要使用 PATH_INFO 来处理请求,并使用 SCRIPT_NAME 和前面的变量一起构成这个可链接.

 

使用 DSL 风格

这 Plack::App::URLMap 有个非常好的 mount 的接口在 DSL 的风格中,你只要在 Plack::Builder 中使用它就可以了,使用 mount 的语法如下:

use Plack::Builder;
builder {
    mount "/john" => $app1;
    mount "/bob"  => builder {
        enable "Auth::Basic", authenticator => ...;
        $app2;
    };
};

请求 ‘/john’ 时做的处理和上面的 URLMap 是一样的,但这个例子中,在 builder 中用户激活了基本认证的模块,所以打开 "/bob" 时需要认证,等同于下面

$app = Plack::App::URLMap->new;
$app->mount("/john", $app1);

$app2 = Plack::Middleware::Auth::Basic->wrap($app2, authenticator => ...);
$app->mount("/bob",  $app2);

但是明显的,使用 DSL 只要更加少的代码和更加容易明白.

 

Multi tenant frameworks

当然你可以使用 URLMap 和 mount 的 API 来运行多个框架的应用在同一个服务器上,假设你有三个应用."Foo" 是基于 Catalyst 开发的,"Bar" 是基于 CGI::Application 开发的,"Baz" 是基于 Squatting 象下面这样.

 

# Catalyst
use Foo;
Foo->setup_engine('PSGI');

my $app1 = sub { Foo->new->run(@_) };

# CGI::Application
use Bar;
use CGI::Application::PSGI;
my $app2 = sub { 
    my $app = Bar->new({ QUERY => CGI::PSGI->new(shift) });
    CGI::Application::PSGI->run($app);
};

# Squatting
use Baz 'On::PSGI';
Baz->init;
my $app3 = sub { Baz->psgi(shift) };

builder {
    mount "/foo" => $app1;
    mount "/bar" => $app2;
    mount "/baz" => $app3;
};

现在你有三个应用,三个应用使用了不同的 web 开发框架,运行在同一个服务器上.使用了不同的路径来打开.

 

这是我的译文,原文:http://advent.plackperl.org/2009/12/day-12-maps-multiple-apps-with-mount-and-urlmap.html

 

来了就留个评论吧! 2个评论



    Matthew 2012年05月30日 的 09:19

    我在CentOS6.2中测试遇到一个问题,请为我解惑,谢谢
    ————————————————–
    use Plack::App::URLMap;
    my $app = Plack::App::URLMap->new;
    $app->mount(“/john” => $app1);
    $app->mount(“/bob” => $app2);
    my $app1 = sub {
    return [ 200, [], [ “Hello John” ] ];
    };
    my $app2 = sub {
    return [ 200, [], [ “Hello Bob” ] ];
    };
    —————————————————
    实际的情况是,无论如何,浏览器都是返回的”Hello Bob”,根据实际观察,对于上面的情况总是运行最后一个app
    这是什么问题呢?

      扶 凯 2012年05月30日 的 09:58

      你程序的
      $app->mount(“/john” => $app1);
      $app->mount(“/bob” => $app2);
      这二行要放在下面.因为变量 $app1 和 $app2 都没有定义.这时会默认使用最后一个 $app2 做为 return .所以会只显示这个.