鉴于 CGI.pm 的弃用状态,我应该从 CGI::Fast 迁移到其他东西吗?我应该怎么做?

Should I migrate from CGI::Fast to something else in light of CGI.pm's deprecated status and how should I do so?

我正在使用 CGI::Fast 来利用 FastCGI 的速度和可扩展性,我还使用 CGI.pm 的查询字符串解析。我不使用 CGI.pm 已弃用的 HTML 编写函数。

停止使用 CGI.pm 在社区中是 strongly advised,但在我的用例中,我是否也应该考虑迁移出去?如果是这样,我该如何

1) 仍然利用 FastCGI

2) 获取查询参数

...没有采用像 Dancer 或 Mojolicious 这样的框架?

我要替换的代码只是:

 while ( $main::cgi = new CGI::Fast ) {
      my $name = $main::cgi->param('name');
 }

我愿意将 CGI::PSGI 之类的东西与 Plack::Request 结合使用,但我看不出如何将 FastCGI 功能巧妙地用作 CGI::FastCGI::PSGI两者都想子类化 CGI 来创建对象。而且我仍然需要 CGI.pm 来启用 CGI::Fast。 Plack好像要学很多东西,替换成现在几行代码。

PSGI, as referenced by CGI::Alternatives,就是要走的路。

Dancer 利用 PSGI,但您可以 write code using it directly 没有围绕它的框架。

您可以通过 FastCGI Plack::Handler::FCGI 运行 PSGI 应用程序。

这巧妙地说明了 PSGI 是对 CGI(及其相关技术,如 FastCGI)的改进的一个原因。在 CGI 风格的程序中,代码与部署方式紧密耦合,当您更改部署方式时,通常需要对代码进行相当大的更改。对于 PSGI 风格的程序,无论您如何部署,代码都是一样的。

您没有向我们展示您的任何代码,但您谈到了 "a few lines of code"。所以这就是我要采用的方法。

  1. 从您的程序中删除所有特定于 FastCGI 的代码 - 留下纯 CGI 风格的程序。
  2. 然后你就可以选择了。您可以使用我在 Easy PSGI to convert your program to a pure PSGI program. Or, if that's going to be too much work, use CGI::PSGI 中描述的技术在 PSGI 环境中 运行 您的 CGI 程序。
  3. 您现在拥有了一个几乎可以在任何网络服务器环境中使用的 PSGI 程序。您可以将其用作 CGI 程序。你可以在 FCGI 下使用 Plack::Handler::FCGI 到 运行 它。或者您可以将其部署为 Web 代理后面的独立服务(我会选择最后一个选项)。

但是您在第 3 步中做出的任何选择都不是不可撤销的。相同的代码将适用于所有部署环境。因此,在它们之间移动通常非常简单。

p.s。 CGI.pm 并未完全弃用。它已从标准 Perl 发行版中删除,但这是因为不鼓励使用它。

这是一份帮助您入门的简短指南。我将使用 CGI,而不是 FastCGI,但它们实际上是一回事。想象一下围绕参数选择的循环。

一个简单的 CGI

让我们从一个简单的CGI 程序开始。我将使用 cgi_this 到 运行 它,因为手边没有真正的 Web 服务器。

#!/usr/bin/env perl
use strict;
use warnings;
use CGI;

my $q    = CGI->new;
my $name = $q->param('name');

print $q->header;
if ($name) {
  print <<"HTML";
<html><body><h1>Hello, $name</hi></body></html>
HTML
}
else {
  print <<"HTML";
<html><body><form method="GET">
    <label>What's your name? <input type="text" name="name"></label>
</form></body></html>
HTML
}

1;

这里是hello.pl。它需要一个可执行标志。

运行 程序

你用 cgi_this 开始,如下所示。

$ ls
hello.pl
$ cgi_this
Exporting '.', available at:
   http://127.0.0.1:3000/

Found the following scripts:
    http://127.0.0.1:3000/hello.pl

现在可以在浏览器中打开了。

如果您输入姓名并提交表单,它会显示问候语。

转换为 PSGI

所有这些都是直截了当的。现在让我们转换它。

我们将从一个名为 hello.psgi 的新文件开始。它是否被称为 .psgi 并不重要,但这是惯例。

我们必须执行几个步骤才能使其适用于 PSGI 协议。我们将使用 Plack::Request 来帮助我们做到这一点。

整个程序需要包含在一个 my $app = sub { ... }; 调用中。

#!/usr/bin/env plackup
use strict;
use warnings;

use Plack::Request;

my $app = sub {
  my $env = shift;    # this is the Plack environment

  my $req = Plack::Request->new($env);

  my $q    = CGI->new;
  my $name = $q->param('name');

  print $q->header;
  if ($name) {
    print <<"HTML";
<html><body><h1>Hello, $name</hi></body></html>
HTML
  }
  else {
    print <<"HTML";
<html><body><form method="GET">
    <label>What's your name? <input type="text" name="name"></label>
</form></body></html>
HTML
  }
};

# no 1; here, we want it to return $app;

现在显然我们还没有加载CGI,反正也没有CGI环境。所以接下来我们需要获取参数。摆脱 $q 位并使用 $req 代替。

my $name = $req->parameters->{name};

现在 运行 使用 plackup,然后在 http://localhost:5000 请求它。

$ plackup hello.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
<html><body><form method="GET">
    <label>What's your name? <input type="text" name="name"></label>
</form></body></html>
Response should be array ref or code ref: 1 at ...

砰!它失败了,因为我们还没有完成。如您所见,它将 HTML 写入 STDOUT,但并未发送至浏览器。那是因为 PSGI 传递引用,而您的程序不直接与 STDOUT 或 STDERR 对话。

它还抱怨缺少参考。让我们先处理一下。在代码参考的末尾,添加:

# prepare the response
my $res = $req->new_response(200);
$res->content_type('text/html');

return $res->finalize;

我们要求我们的 Plack::Request 为我们创建一个新的 Plack::Response,设置内容类型,然后 return 最终确定(想想 immutable) 对 Plack 处理程序的响应,它将序列化并作为实际的 HTTP 响应发送给浏览器。

现在替换所有 print 语句。创建一个新变量 $content 而不是 printing 输出,将其连接到该变量。然后将其交给响应。

  my $content;
  if ($name) {
    $content .= <<"HTML";
<html><body><h1>Hello, $name</hi></body></html>
HTML
  }
  else {
    $content .= <<"HTML";
<html><body><form method="GET">
    <label>What's your name? <input type="text" name="name"></label>
</form></body></html>
HTML
  }

  # prepare the response
  my $res = $req->new_response(200);
  $res->content_type('text/html');
  $res->body($content);

现在在终端中重新启动您的应用程序并再次访问它。它看起来和 CGI​​ 一样。