10

Plack::Builder允许挂载多个主机,例如以下代码段:

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 { ... };
}

例如

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

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

然而,Plack 的作者自己说(在Plack::Request中)

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

直接使用 Plack::Request 编写您的 Web 应用程序当然是可能的,但不建议这样做:这就像使用 mod_perl 的 Apache::Request: 这样做一样,但是级别太低了。

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

这就是问题所在。

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

所以问题是:

  • 我错过了 MetaCPAN(或文档)中的某些内容,并且这里存在 任何app.psgi(轻量级)网络框架,它允许开发可在?中多次安装的应用程序。
  • 还是我被迫发展Just Another My Own PSGI Framework?(老实说,我没有检查催化剂——因为它太重了)
  • 或者只是对“安装”有很深的理解?
4

2 回答 2

1

在 Plack 中构建调度程序

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

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

example.org
example.com
example.de
example.am
example.cx

或使用以下子域:

one.example.org
two.example.org
three.example.org
four.example.org
five.example.org
six.example.org

那么这就完美了。另一方面,我不确定它是否支持也具有恒定路径部分的 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} );
}

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

 $host_map->map( "example.org" => sub { ... } );

用于执行此操作的 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;

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"

这个想法是使用相同的包文件并将其子类化以在 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;

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

于 2017-02-10T01:23:59.400 回答
1

我相信引用的文档更多地用于 Plack::Request 而不是 Plack::Builder。

使用 Plack::Builder 安装各种应用程序(例如 Dancer/Catalyst/Mojolicious/homegrown 应用程序)是完全可以接受的,这确实很常见。

于 2017-02-17T13:11:40.707 回答