【问题标题】:How can I run a CGI::Application run mode from the command line?如何从命令行运行 CGI::Application 运行模式?
【发布时间】:2011-05-04 21:51:06
【问题描述】:

我的CGI::Application web 应用程序中有一个运行模式,我希望能够从命令行触发它,以便实现自动化。从 Web 应用的角度来看,它会进行一些处理,然后通过电子邮件发送结果。

当从 Web 界面调用时,它会传入一组参数(电子邮件地址、要运行的查询、日期等),因此需要传入这些参数。

如何构造一个对 CGI::Application 应用程序的调用,它与我从网络上运行它时一样?

【问题讨论】:

    标签: perl cgi-application


    【解决方案1】:

    原来的CGI specification 使得从命令行运行东西变得很容易,并且完全不是作为一个特定的 HTTP-only 接口,而是可以处理 FTP 和 gopher 以及新的顶级 URL 方案的东西。当我帮助指定它时,我知道我想要什么。

    我引用的规范应该可以满足您的所有需求,但在大多数情况下,它只是环境变量的集合。如果您看到以下请求:

    http://some.server.com/some/path?a=b&c=d
    

    环境变量如下所示:

    SERVER_PROTOCOL=http
    REQUEST_METHOD=GET
    HTTP_HOST=some.server.com
    SERVER_PORT=80
    PATH_INFO=/some/path
    QUERY_INFO=a=b&c=d
    

    要反转 Perl 中的极性,可以这样:

    $ENV{'SERVER_PROTOCOL'} = 'http';
    $ENV{'REQUEST_METHOD'} = 'GET';
    $ENV{'SERVER_PORT'} = 80;
    $ENV{'PATH_INFO'} = '/some/path';
    $ENV{'QUERY_INFO'} = 'a=b&c=d';
    system("perl your-CGI-script.pl");
    

    在处理 POST 查询时事情变得有点复杂,并且可能需要更多可能的环境变量。最坏的情况,你可以用一个快速的 CGI 脚本来枚举它们,比如:

    print "Content-Type: text/plain\r\n\r\n";
    foreach (keys(%ENV))
    {
        print "$_=$ENV{$_}\r\n";
    }
    

    现在将它放在网络服务器上代替您的 CGI 脚本,您将看到传入的所有环境(以及原始环境,因此您需要进行一些判断调用)。

    【讨论】:

    • 当我这样做时,我通常使用 exec。不过没什么大不了的。
    • 酷,你帮助指定了 CGI。 :)
    【解决方案2】:

    在进一步研究 CGI::App 和 CGI 文档后,它似乎比我想象的要简单。最简单的情况(没有真正的参数处理或处理来自 webapp 运行调用的输出)是:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use CGI;
    use WebApp;
    
    my $cgi = new CGI( \%{@ARGV} );
    
    my $webapp = WebApp->new( QUERY => $cgi );
    $webapp->run();
    

    创建 CGI 只需要一系列空格分隔的名称值对。您需要传入运行模式和所有参数。

    【讨论】:

    • 没错,'your_script.pl name1=value1 name2=value2' 表单适用于运行基本的 CGI::App .cgi 文件,但是我将失去任何控制输入、设置默认值等的能力。
    • 此示例仍将打印到 STDOUT,包括 HTTP 标头,这是不可取的。此外,不需要涉及 CGI.pm。当您使用标准参数处理工具(如 Getopt::Long)直接从命令行传递和处理参数时,它只会使事情变得混乱。
    【解决方案3】:

    我是 CGI::Application 的维护者,我一直都在这样做——我有十几个用 CGI::Application 构建的 cron 脚本,因为与应用程序共享基础架构很方便。

    最简单的方法是这样的:

    # There is no browser to return results to.
    $ENV{CGI_APP_RETURN_ONLY} = 1;
    
    my $app = WebApp->new;
    $app->direct_run_mode_method;
    

    在该示例中,您绕过正常流程并直接调用方法。确保在这种情况下您不需要任何“设置”或“拆卸”操作。

    如果你只调用了一种运行模式,你也可以只设置“start_mode”,然后调用run(),这样就默认调用了默认的运行模式。

    另一个想法:您可以使用 Getopt::Long 之类的模块,并通过 PARAM 哈希将值传递给 new(),或者完全替换运行模式选择过程。这是一个使用命令行标志来确定运行模式的示例:

    sub setup {
        my $self = shift;
    
        $self->start_mode('send_error_digests');
        $self->run_modes([qw/
            send_error_digests
            help
        /]);
    
        my ($dry_run, $help);
        GetOptions(
            'dry-run' => \$dry_run,
            'help'    => \$help
        );
    
        $self->param('dry_run' => $dry_run);
    
        $self->mode_param(sub {
            return 'help' if $help;
            return $self->start_mode();
        });
    }
    

    【讨论】:

      【解决方案4】:

      因此:

      $ perl yourscript.pl  field1=value1 field2=value2
      

      Perl 的 CGI 库为您提供了魔法,看起来 CGI::Application 依赖于 CGI(从他们的示例代码来看)。

      【讨论】:

      • 您还需要设置各种环境变量来模拟 Web 服务器设置的内容。 CGI.pm 会寻找那些,所以它知道该做什么。
      • @brian d foy:除非您的代码出于某种原因依赖于这些,否则不会;没有它们,CGI.pm 也能正常工作。
      • @ysth:如果这种运行模式有副作用,它应该使用 POST,因为它不是幂等请求。在这种情况下,您必须将 -debug 添加到 CGI.pm 的导入中以允许这些东西工作。这是对代码的更改,它也有副作用。正如乔治所说,这样做要容易得多。
      【解决方案5】:

      不必每次想要完成某事时都通过 CGI::Application 执行正确的separation of concerns,也许使用MVC 设置。所有的功能都应该存在于 CGI::Application 之外,因为它只能作为控制器工作。分离出这些位后,您可以轻松地为其他输入法编写其他控制器。

      不要编写网络应用程序;编写一个恰好具有 Web 界面的应用程序。有了这些,您就可以轻松地为您的应用程序提供其他类型的接口。

      【讨论】:

      • 我完全同意,有一个库可以执行生成结果的实际工作,我试图限制 CGI::A 的“控制器”部分中的代码量它只是格式化的地方。只是我的“懒惰”部分认为我可以使用 CGI::App 发送电子邮件,而不是编写另一个脚本来调用库。
      • 嗯,大写 L 的懒惰可以让你轻松地完成其他任务而无需未来的工作:懒惰不是避免工作,而是为了节省时间的前期工作。
      • (必须提到 YAGNI,虽然我大部分时间都倾向于在大写 L 模式下操作)
      • 在他实际要求的情况下提及 YAGNI 具有讽刺意味。
      【解决方案6】:

      您可以通过使用 curl、wget 或带有适当参数的 LWP GET 脚本调用 Web 应用程序来实现自动化。我在 Catalyst 应用程序中使用了类似的系统来执行 cron 驱动的任务。

      它为您处理所有环境变量..

      【讨论】:

      • 这个解决方案增加了一个额外的问题需要解决:现在你必须确保 cron 作业的 URI 受到保护,这样它只能从 cron 作业中访问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-22
      • 1970-01-01
      • 2023-01-14
      • 2010-10-29
      • 2011-03-19
      • 2021-12-03
      • 2012-08-07
      相关资源
      最近更新 更多