多站点感知PSGI应用程序开发

kob*_*ame 10 perl plack psgi

普拉克::生成器允许挂接多个主机,例如一些如下面的代码片段:

my @sites = load_site_names();
my $apps;
for my $site (@sites) {
    $apps->{$site} = Some::PsgiFramework::MyApp->new( config => get_config($site) );
}

use Plack::Builder;
builder {
    for my $site (@sites) {
        mount "$site" => $apps->{$site};
    }
    mount '/' => sub { ... };
}
Run Code Online (Sandbox Code Playgroud)

例如

  • load_site_names返回站点的列表一样http://example.com,http://some.other.site.com...
  • 每个"虚拟主机"都会使用相同的 Some::PsgiFramework::MyApp
  • 只是他们的配置不同

我完全需要以上内容 - 需要开发一个简单的网络应用程序,该应用程序应该部署在不同(低流量)站点的数据库中,并且不希望为每个站点设置不同的PSGI服务器.

然而,Plack本身的作者说(在Plack :: Request中)

请注意,此模块旨在供Plack中间件开发人员和Web应用程序框架开发人员而非应用程序开发人员(最终用户)使用.

使用Plack :: Request直接编写Web应用程序当然是可行的,但不推荐:它就像使用mod_perl的Apache :: Request那样:但是程度太低.

如果您正在编写Web应用程序而不是框架,那么建议您使用一个支持PSGI的Web应用程序框架(http://plackperl.org/#frameworks),或者查看HTTP :: Engine等模块在PSGI之上提供更高级别的请求和响应API.

这就是问题所在.

我在MetaCPAN中检查了许多不同的基于PSGI的框架.并且AFAIK每个都是基于单一的,例如,不允许写入应用程序可以多次共享(安装)同一个不同的站点app.psgi.

所以问题是:

  • 错过了我在MetaCPAN(或文档)中的东西,这里存在 任何(轻量级)web框架,它允许开发应用程序可以多次挂载app.psgi
  • 或者我被迫发展Just Another My Own PSGI Framework?(老实说,我没有检查催化剂 - 因为它太重了)
  • 或者只是很难理解"安装"?

sim*_*que 1

在 Plack 中构建调度程序

Plack::App::URLMap 有一个替代方案,称为Plack::App::HostMap,它的查找速度更快,因为它内部使用散列,而不是数组。所以没有进行迭代。它只是进行哈希查找,而这些在 Perl 中速度非常快。

代价是现在您只能使用常量主机名。因此,如果您的列表是这样的:

example.org
example.com
example.de
example.am
example.cx
Run Code Online (Sandbox Code Playgroud)

或者使用子域,例如:

one.example.org
two.example.org
three.example.org
four.example.org
five.example.org
six.example.org
Run Code Online (Sandbox Code Playgroud)

那么这就完美了。另一方面,我不确定它是否支持也具有恒定路径部分的 URL,例如http://foo.example.org/bar,其中有很多foos,但它们都共享/bar安装应用程序的相同路径。该模块根本没有任何测试,我无法尝试。如果您查看这些更改,就会发现至少有一个人建议添加其他功能,因此除作者之外的其他人正在使用它。

要使用它,您可以从 Plack::Builder 切换到使用 Plack::App::HostMap 作为您调用方法的应用程序。

use Plack::App::HostMap;

# set up %apps (e.g. foo.example.org, bar.example.org)

my $host_map = Plack::App::HostMap->new;

for my $site (@sites) {
    $host_map->map( $site => $apps->{$site} );
}
Run Code Online (Sandbox Code Playgroud)

您没有告诉我们该/路线应该做什么,但本质上它还需要一个主机。如果您的服务器有很多主机名,那么所有主机名都会响应此请求。这就是你想做的事情的全部想法。但是主机名的用途是什么/?因此,最好的办法是为sub { ... }斜线应用程序添加一条带有真实主机名的附加行。也许那是一个控制面板之类的。所以将其连接到实际的 URL。

 $host_map->map( "example.org" => sub { ... } );
Run Code Online (Sandbox Code Playgroud)

一个用于执行此操作的 Web 框架

单例并不是真正的问题。似乎不可能让 Dancer2 使用相同的配置或环境加载不同的配置或环境。对于这个用例,我还没有尝试过 Mojo、Web::Simple 或 Catalyst。

我确实尝试了很多 D2,最接近的是/在 MyApp 和这个 PSGI 应用程序中拥有一条路线。请注意,这不起作用

use Plack::Builder;

my $builder = Plack::Builder->new;
foreach my $name (qw/development production/) {
    $builder->mount(
        "/$name" => builder {
            eval <<"APP";
package MyApp::$name {
    use Dancer2;
    use MyApp with => { environment => "$name" };
}
APP

            "MyApp::$name"->to_app;
        }
    );
}

$builder->to_app;
Run Code Online (Sandbox Code Playgroud)

它使用使用未更改的环境文件生成的默认框架dancer2 -a MyApp。Plack 的调度有效,但 Dancer2 感到困惑。

HTTP::Server::PSGI: Accepting connections at http://0:5000/
[MyApp::production:4896] core @2017-02-10 02:14:42> looking for get / in /home/julien/perl5/perlbrew/perls/perl-5.20.1/lib/site_perl/5.20.1/Dancer2/Core/App.pm l. 35
[MyApp::production:4896] core @2017-02-10 02:14:42> Entering hook core.error.init in (eval 49) l. 1
[MyApp::production:4896] core @2017-02-10 02:14:42> Entering hook core.error.before in (eval 49) l. 1
[MyApp::production:4896] core @2017-02-10 02:14:42> Entering hook core.error.after in (eval 49) l. 1
127.0.0.1 - - [10/Feb/2017:02:14:42 +0100] "GET /production/ HTTP/1.1" 404 456 "-" "curl/7.47.0"
[MyApp::development:4896] core @2017-02-10 02:18:06> looking for get  in /home/julien/perl5/perlbrew/perls/perl-5.20.1/lib/site_perl/5.20.1/Dancer2/Core/App.pm l. 35
[MyApp::development:4896] core @2017-02-10 02:18:06> Entering hook core.error.init in (eval 49) l. 1
[MyApp::development:4896] core @2017-02-10 02:18:06> Entering hook core.error.before in (eval 49) l. 1
[MyApp::development:4896] core @2017-02-10 02:18:06> Entering hook core.error.after in (eval 49) l. 1
127.0.0.1 - - [10/Feb/2017:02:18:06 +0100] "GET /development HTTP/1.1" 404 457 "-" "curl/7.47.0"
Run Code Online (Sandbox Code Playgroud)

这个想法是使用相同的包文件并将其子类化以在 via 中获取不同的配置with

但是,可以在循环中一遍又一遍地定义相同的应用程序。您可能可以使用代码引用将路由处理程序移出get '/' => \&main::get_slash,例如 ,其中sub get_slash不在eval.

use Plack::Builder;

my $builder = Plack::Builder->new;
foreach my $name (qw/development production/) {
    $builder->mount(
        "/$name" => builder {
            eval <<"APP";
package MyApp::$name {
use Dancer2;
    use Data::Printer;

    set environment => "$name";

    get "/" => sub { np(config) }
}
APP

            "MyApp::$name"->to_app;
        }
    );
}

$builder->to_app;
Run Code Online (Sandbox Code Playgroud)

该字符串eval并不像看起来那么邪恶,因为该代码仅在启动时运行。D2 将在内部跟踪您在此处以编程方式创建的所有应用程序。但我不知道它的性能如何。