内容

NAME

perlfaq9 - 网页、电子邮件和网络

VERSION

版本 5.20210520

DESCRIPTION

本节讨论与运行网站、发送和接收电子邮件以及一般网络相关的疑问。

我应该使用 Web 框架吗?

是的。如果您正在构建具有任何交互性级别的网站(表单/用户/数据库),您将需要使用框架来简化请求和响应的处理。

如果没有交互性,您可能仍然需要考虑使用 Template ToolkitPlack::Middleware::TemplateToolkit 之类的东西,以便更轻松地维护您的 HTML 文件(和其他资产)。

我应该使用哪个 Web 框架?

这个问题没有简单的答案。Perl 框架可以运行从基本文件服务器和小型内部网到大型跨国多语言网站,这些网站是国际业务的核心。

以下是几个框架的列表,以及一些评论,这些评论可能有助于您根据您的具体要求做出决定。首先阅读文档,然后在相关的邮件列表或 IRC 频道上提问。

Catalyst

强面向对象且功能齐全,拥有悠久的开发历史和庞大的社区和插件生态系统。它非常适合大型复杂应用程序,您可以在其中完全控制服务器。

Dancer2

没有遗留负担,提供轻量级且易于学习的 API。拥有不断增长的插件生态系统。它最适合小型项目,初学者很容易学习。

Mojolicious

对于小型和大型项目来说都是自包含且功能强大的,重点关注 HTML5 和实时 Web 技术,例如 WebSockets。

Web::Simple

强面向对象且最小化,专为速度而构建,旨在作为构建微型 Web 应用程序、自定义框架或将现有 Plack 兼容 Web 应用程序与一个中央调度器连接在一起的工具包。

所有这些都与 Plack 交互或使用它,在使用 Perl 构建网站时,了解它的基础知识非常重要(有很多有用的 Plack::Middleware)。

什么是 Plack 和 PSGI?

PSGI 是 Perl Web 服务器网关接口规范,它是许多 Perl Web 框架使用的标准,您不需要理解它来构建网站,您可能想使用的部分是 Plack

Plack 是一组用于使用 PSGI 堆栈的工具。它包含 中间件 组件、参考服务器和 Web 应用程序框架的实用程序。Plack 类似于 Ruby 的 Rack 或 Python 的 Paste for WSGI。

您可以使用 Plack 和您自己的代码构建网站,但对于除最基本的网站以外的任何网站,使用 Web 框架(使用 https://plackperl.org)是一个更好的选择。

如何从字符串中删除 HTML?

使用 HTML::StripHTML::FormatText,它不仅删除 HTML,而且还尝试对生成的纯文本进行一些简单的格式化。

如何提取 URL?

HTML::SimpleLinkExtor 将从 HTML 中提取 URL,它处理锚点、图像、对象、框架以及许多其他可能包含 URL 的标签。如果您需要更复杂的操作,您可以创建 HTML::LinkExtorHTML::Parser 的子类。您甚至可以使用 HTML::SimpleLinkExtor 作为专门适合您需求的示例。

您可以使用 URI::FindURL::Search 从任意文本文档中提取 URL。

如何获取 HTML 文件?

(由 brian d foy 贡献)

核心 HTTP::Tiny 模块可以获取 Web 资源并将它们的内容作为字符串返回给您

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;
my $html = $ua->get( "http://www.example.com/index.html" )->{content};

它还可以将资源直接存储在文件中

$ua->mirror( "http://www.example.com/index.html", "foo.html" );

如果您需要执行更复杂的操作,可以通过设置属性来定制 HTTP::Tiny 对象,或者您可以使用 libwww-perl 发行版中的 LWP::UserAgent 或 Mojolicious 发行版中的 Mojo::UserAgent 来简化常见任务。如果您想模拟交互式 Web 浏览器,可以使用 WWW::Mechanize 模块。

如何自动执行 HTML 表单提交?

如果您正在执行复杂的操作,例如在多个页面和表单或网站之间移动,可以使用 WWW::Mechanize。有关所有详细信息,请参阅其文档。

如果您使用 GET 方法提交值,请创建一个 URL 并使用 HTTP::Tiny 中的 www_form_urlencode 方法对表单进行编码。

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;

my $query = $ua->www_form_urlencode([ q => 'DB_File', lucky => 1 ]);
my $url = "https://metacpan.org/search?$query";
my $content = $ua->get($url)->{content};

如果您使用 POST 方法,post_form 方法将适当地对内容进行编码。

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;

my $url = 'https://metacpan.org/search';
my $form = [ q => 'DB_File', lucky => 1 ];
my $content = $ua->post_form($url, $form)->{content};

如何在 Web 上解码或创建这些 %-编码?

大多数情况下,您不需要这样做,因为您的 Web 框架,或者如果您正在发出请求,LWP 或其他模块会为您处理它。

要自己对字符串进行编码,请使用 URI::Escape 模块。uri_escape 函数返回转义后的字符串。

my $original = "Colon : Hash # Percent %";

my $escaped = uri_escape( $original );

print "$escaped\n"; # 'Colon%20%3A%20Hash%20%23%20Percent%20%25'

要解码字符串,请使用 uri_unescape 函数。

my $unescaped = uri_unescape( $escaped );

print $unescaped; # back to original

请记住,不要对完整的 URI 进行编码,您需要分别转义每个组件,然后将它们组合在一起。

如何重定向到另一个页面?

大多数 Perl Web 框架都具有执行此操作的机制,使用 Catalyst 框架,它将是

$c->res->redirect($url);
$c->detach();

如果您使用的是 Plack(大多数框架都使用),那么如果您要从 Apache 迁移或有要始终重定向的 URL,则 Plack::Middleware::Rewrite 值得一看。

如何在网页上设置密码?

查看您正在使用的 Web 框架是否具有身份验证系统,以及它是否适合您的需求。

或者,查看 Plack::Middleware::Auth::Basic 或其他 Plack 身份验证 选项。

如何确保用户无法输入会导致我的 CGI 脚本执行错误操作的值?

(由 brian d foy 贡献)

您无法阻止人们向您的脚本发送错误数据。即使您添加了一些客户端检查,人们也可能禁用它们或完全绕过它们。例如,有人可能会使用 LWP 等模块提交到您的网站。如果您想阻止尝试使用 SQL 注入或其他攻击类型的数据(您应该想要阻止),那么您必须不信任进入程序的任何数据。

有关数据安全的通用建议,请参阅 perlsec 文档。如果您使用的是 DBI 模块,请使用占位符来填充数据。如果您使用 systemexec 运行外部程序,请使用列表形式。还有许多其他预防措施需要您采取,这里无法一一列举,其中大多数都属于不要使用任何您不打算使用的数据的范畴。不要相信任何人。

如何解析邮件头?

使用 Email::MIME 模块。它经过充分测试,支持您在现实世界中遇到的所有复杂情况(注释折叠空格、编码、注释等)。

use Email::MIME;

my $message = Email::MIME->new($rfc2822);
my $subject = $message->header('Subject');
my $from    = $message->header('From');

如果您已经拥有其他类型的电子邮件对象,请考虑将其传递给 Email::Abstract,然后使用其 cast 方法获取 Email::MIME 对象。

my $abstract = Email::Abstract->new($mail_message_object);
my $email_mime_object = $abstract->cast('Email::MIME');

如何检查有效的邮件地址?

(部分由 Aaron Sherman 贡献)

这个问题并不像看起来那么简单。它包含两个部分:

a) 如何验证电子邮件地址是否格式正确?

b) 如何验证电子邮件地址是否指向有效的收件人?

如果不向地址发送邮件并查看是否有真人回复,您无法完全回答问题 b,但 Email::Valid 模块将在实时情况下尽可能地完成问题 ab

我们建议您验证一个人的邮件地址的最佳方法是让他们输入两次地址,就像您通常更改密码一样。这通常可以消除打字错误。如果两个版本匹配,请向该地址发送包含个人信息的邮件。如果您收到回信,并且他们按照您的指示操作,您可以确信该地址是真实的。

另一种不易被伪造的策略是给他们一个 PIN(个人识别码)。记录地址和 PIN(最好是随机的),以便稍后处理。在您发送的邮件中,包含一个指向您网站的链接,其中包含 PIN。如果邮件弹回,您就知道它无效。如果他们没有点击链接,要么是他们伪造了地址,要么是(假设他们收到了邮件)他们没有认真对待,所以您不必担心。

如何解码 MIME/BASE64 字符串?

The MIME::Base64 包处理此问题以及 MIME/QP 编码。解码 base 64 变得像这样简单

use MIME::Base64;
my $decoded = decode_base64($encoded);

The Email::MIME 模块可以透明地解码 base 64 编码的电子邮件消息部分,因此开发人员无需担心它。

如何找到用户的邮件地址?

向他们索取。有如此多的电子邮件提供商可用,本地系统不太可能知道如何确定用户的电子邮件地址。

例外情况是针对组织特定的电子邮件(例如 [email protected]),其中策略可以在您的程序中进行编码。在这种情况下,您可以查看 $ENV{USER}、$ENV{LOGNAME} 并以标量上下文获取 getpwuid($<),如下所示

my $user_name = getpwuid($<)

但是您仍然不能假设这是否正确,除非您的策略说它是。您真的最好询问用户。

如何发送电子邮件?

使用 Email::Stuffer 模块,如下所示

# first, create your message
my $message = Email::Stuffer->from('[email protected]')
                            ->to('[email protected]')
                            ->subject('Happy birthday!')
                            ->text_body("Happy birthday to you!\n");

$message->send_or_die;

默认情况下,Email::Sender::Simplesendsend_or_die 方法在幕后使用它)将首先尝试 sendmail,如果它存在于您的 $PATH 中。这通常不是这种情况。如果您使用远程邮件服务器发送邮件,请考虑调查其中一个传输类。在撰写本文时,可用的传输包括

Email::Sender::Transport::Sendmail

这是默认值。如果您可以在运行代码的机器上使用 mail(1)mailx(1) 程序发送邮件,则应该可以使用它。

Email::Sender::Transport::SMTP

此传输通过 TCP 联系远程 SMTP 服务器。它可以选择使用 TLS 或 SSL,并且可以通过 SASL 对服务器进行身份验证。

告诉 Email::Stuffer 使用您的传输很简单。

$message->transport($email_sender_transport_object)->send_or_die;

如何使用 MIME 将附件添加到邮件消息?

Email::MIME 直接支持多部分消息。 Email::MIME 对象本身是部分,可以附加到其他 Email::MIME 对象。有关更多信息,包括所有支持的方法和使用示例,请参阅 Email::MIME 文档。

Email::Stuffer 在幕后使用 Email::MIME 来构建消息,并使用简单的 attachattach_file 方法包装最常见的附件任务。

Email::Stuffer->to('[email protected]')
              ->subject('The file')
              ->attach_file('stuff.csv')
              ->send_or_die;

如何阅读电子邮件?

使用 Email::Folder 模块,如下所示

use Email::Folder;

my $folder = Email::Folder->new('/path/to/email/folder');
while(my $message = $folder->next_message) {
  # next_message returns Email::Simple objects, but we want
  # Email::MIME objects as they're more robust
  my $mime = Email::MIME->new($message->as_string);
}

Email::Folder 命名空间中,有不同类别的模块用于支持各种邮箱类型。请注意,这些模块通常功能有限,只支持 **读取** 而不是写入。

如何获取我的主机名、域名或 IP 地址?

(由 brian d foy 贡献)

从 Perl 5.7.3 开始,Net::Domain 模块是标准库的一部分,可以获取完全限定域名 (FQDN)、主机名或域名。

use Net::Domain qw(hostname hostfqdn hostdomain);

my $host = hostfqdn();

标准库中的 Sys::Hostname 模块也可以获取主机名。

use Sys::Hostname;

$host = hostname();

Sys::Hostname::Long 模块采用不同的方法,并尽力返回完全限定的主机名。

use Sys::Hostname::Long 'hostname_long';

my $hostname = hostname_long();

要获取 IP 地址,可以使用 gethostbyname 内置函数将名称转换为数字。要将该数字转换为大多数人期望的点分十进制形式 (a.b.c.d),请使用 Socket 模块中的 inet_ntoa 函数,该模块也随 Perl 一起提供。

use Socket;

my $address = inet_ntoa(
    scalar gethostbyname( $host || 'localhost' )
);

如何获取/上传 (S)FTP 文件?

Net::FTPNet::SFTP 允许您与 FTP 和 SFTP(安全 FTP)服务器交互。

如何在 Perl 中进行 RPC?

使用其中一个 RPC 模块(https://metacpan.org/search?q=RPC)。

作者和版权

版权所有 (c) 1997-2010 Tom Christiansen、Nathan Torkington 和其他作者(如已注明)。保留所有权利。

本文档是免费的;您可以根据与 Perl 本身相同的条款重新分发和/或修改它。

无论其分发方式如何,本文件中所有代码示例均在此置于公有领域。您被允许并鼓励在您自己的程序中使用此代码,无论是出于娱乐目的还是为了盈利,这取决于您的意愿。在代码中添加一个简单的注释以表示感谢将是礼貌的,但不是必需的。