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

标签 perl plack psgi

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 中)

    Note that this module is intended to be used by Plack middleware developers and web application framework developers rather than application developers (end users).

    Writing your web application directly using Plack::Request is certainly possible but not recommended: it's like doing so with mod_perl's Apache::Request: yet too low level.

    If you're writing a web application, not a framework, then you're encouraged to use one of the web application frameworks that support PSGI (http://plackperl.org/#frameworks), or see modules like HTTP::Engine to provide higher level Request and Response API on top of PSGI.



    这就是问题所在。

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

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

    在 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 ,其中有很多 foo ,但它们都共享安装应用程序的相同 /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"
    

    这个想法是使用相同的包文件并将其子类化以通过 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 将在内部跟踪您在此处以编程方式创建的所有应用程序。但我不知道它的性能如何。

    关于perl - 多站点感知 PSGI 应用程序开发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36230563/

    相关文章:

    perl - 如何推迟 <head> 渲染?

    perl - 使用 Perl 解压缩 LZ4 blob

    perl - Starman 和 MovableType 5.2

    perl - 如何使用 Test::WWW::Mechanize::PSGI 测试 Dancer 应用程序?

    perl - 污染和污染模式

    regex - perl regex 查找任何 5 的倍数

    perl - Getopt::Long::Descriptive - 选项规范错误:

    perl - 窥探不同 plack 中间件之间的 http header

    perl - 在 Plack 中发送无缓冲响应

    perl - 将自定义环境变量设置为 psgi hash pack