名称

Mojolicious::Guides::Cookbook-用Mojolicous烹饪

概述

本文档包含许多有趣的烹饪食谱Mojolicious公司.

概念

Essentials每Mojolicious公司开发人员应该知道。

阻塞和非阻塞操作

A类舞台调度操作是一个子程序,它阻止调用子程序的执行,直到子程序完成。

子foo{my$result=块子例程();...}

A类非阻塞另一方面,操作允许调用子例程继续执行,即使子例程尚未完成。调用子例程不是等待,而是传递一个回调,以便在子例程完成后执行,这被称为继续传递样式。

子foo{非阻塞子例程(sub($result){...});...}

While期间Mojolicious公司已经从头开始为非阻塞I/O和事件循环设计,不可能神奇地使Perl代码非阻塞。您必须使用通过以下模块提供的专用非阻塞代码Mojo::IOLoopMojo::用户代理或第三方事件循环。您可以将阻塞代码封装在子流程尽管这样可以防止它干扰您的非阻塞代码。

事件循环

事件循环基本上是一个不断测试外部事件并执行适当回调以处理它们的循环,它通常是程序中的主循环。文件描述符和计时器的可读性/可写性的非阻塞测试是高度可扩展网络服务器的常用事件,因为它们允许单个进程并发处理数千个客户端连接。

而(1){我的@readable=test_fds_for_readability();handle_readable_fds(@可读);my@writable=test_fds_for_writability();handle_writable_fds(@writable);my@expired=test_timers();handle_timers(@过期);}

Mojolicious公司此事件循环是Mojo::IOLoop.

反向代理

反向代理体系结构是一种在许多生产环境中使用的部署技术,其中反向代理服务器放在应用程序前面,充当外部客户端可访问的端点。它可以提供很多好处,比如从外部终止SSL连接,限制面向Mojolicios应用程序的并发打开套接字数量(甚至使用Unix套接字),跨多个实例平衡负载,或者通过同一IP/端口支持多个应用程序。

..........................................:                                        :+--------+      :  +-----------+      +---------------+  :|        |-------->|           |      |               |  :|client|:|reverse|----->|Mojolicious|:||<---------|proxy||应用程序|:+--------+      :  |           |<-----|               |  ::  +-----------+      +---------------+  ::                                        :..系统边界(例如同一主机)。。。。。。

然而,这种设置带来了一些问题:应用程序将从反向代理而不是原始客户端接收请求;应用程序内部的地址/主机名与从外部可以看到的不同;如果终止SSL,则反向代理通过HTTPS公开服务,同时向Mojolicus应用程序使用HTTP。

例如,比较来自客户端的示例请求和Mojolicious应用程序接收到的请求:

客户端反向代理Mojolicious应用程序__|__              _______________|______________             ____|____/     \            /                              \           /         \1.2.3.4--HTTPS-->api.example.com 10.20.30.39--HTTP-->10.20.30.40GET/foo/1 HTTP/1.1 | GET/foo/1 HTTP/1主持人:api.example.com |主持人:10.20.30.40用户代理:Firefox |用户代理:ShinyProxy/1.2...                                |    ...

然而,现在客户端地址不再可用(这可能对分析或Geo-IP有用),并且通过以下方式生成URLMojolicious::Controller中的“url_for”将如下所示:

http://10.20.30.40/bar/2

而不是像这样对客户有意义的东西:

https://api.example.com/bar/2

要解决这些问题,可以配置反向代理以发送丢失的数据(请参阅“Nginx”“Apache/mod_proxy”)并通过设置环境变量告诉您的应用程序MOJO_REVERSE_PROXY公司。在更复杂的情况下,通常涉及多个代理或位于网络外部的代理,可能需要通过设置MOJO_受信任_代理以逗号分隔的地址或CIDR网络列表。为了实现更精细的控制,“正在重写”包括如何手动实现更改的示例。

部署

得到Mojolicious公司Mojolicious::精简在不同平台上运行的应用程序。请注意,许多实时web功能都基于Mojo::IOLoop事件循环,因此需要一个内置的web服务器能够充分利用它们。

内置web服务器

Mojolicious公司包含一个非常便携的非阻塞I/O HTTP和WebSocket服务器Mojo::服务器::守护进程。它通常用于开发和构建更高级的web服务器,但对于中小型应用程序来说,它足够坚固和快速。

$ ./script/my_app守护程序Web应用程序位于http://127.0.0.1:3000

每个应用程序都可以通过命令使用它Mojolicous::命令::守护进程,它有许多配置选项,众所周知,它可以在Perl使用其单进程体系结构的每个平台上工作。

$ ./script/my_app守护程序-h…可用选项列表。。。

另一个巨大的优势是,它支持TLS和WebSockets,内置了用于测试的开发证书,因此它可以正常工作,但您可以指定支持的所有侦听位置Mojo::Server::Daemon中的“listen”.

$ ./script/my_app守护进程-l https://[::]:3000Web应用程序位于https://[::]:3000

要使用systemd管理web服务器,可以使用这样的单元配置文件。

[单位]Description=我的Mojolicios应用程序之后=网络目标【服务】类型=简单用户=sriExecStart=/home/sri/myapp/script/my_app daemon-m production-l http://*:8080[安装]WantedBy=多用户目标

前馈

对于更大的应用程序Mojolicious公司包含UNIX优化的预分叉web服务器Mojo::服务器::Prefork,它可以利用多个CPU内核和复制写入内存管理来扩展到数千个并发客户端连接。

Mojo::服务器::Prefork|-Mojo::服务器::守护程序[1]|-Mojo::服务器::守护进程[2]|-Mojo::服务器::守护进程[3]+-Mojo::服务器::守护程序[4]

它基于Mojo::服务器::守护进程并通过命令对每个应用程序可用Mojolicious::命令::prefork.

$ ./脚本/my_app预处理Web应用程序位于http://127.0.0.1:3000

由于所有内置web服务器都基于Mojo::IOLoop事件循环,它们在非阻塞操作中的伸缩性最好。但是,如果应用程序出于某种原因需要执行许多阻塞操作,则可以通过增加工作进程的数量和减少每个工作进程允许处理的并发连接的数量(通常低至1).

$ ./script/my_app预处理-m生产-w 10-c 1Web应用程序位于http://127.0.0.1:3000

在启动期间,您的应用程序被预加载到管理器进程中,该进程不运行事件循环,因此您可以使用Mojo::IOLoop中的“next_tick”每当一个新的工作进程被分叉并开始其事件循环时,都要运行代码。

使用Mojolicious::Lite;Mojo::IOLoop->next_tick(sub($IOLoop){app->log->info(“Worker$$star……HYPNOTOAD万岁!”);});get'/'=>{text=>'你好,Wor……HYPNOTOAD万岁!'};应用程序->启动;

要使用systemd管理预分叉web服务器,可以使用这样的单元配置文件。

[单位]Description=我的Mojolicios应用程序之后=网络目标【服务】类型=简单用户=sriExecStart=/home/sri/myapp/script/my_app prefork-m production-l http://*:8080[安装]WantedBy=多用户目标

莫尔博

阅读后Mojolicious::指南::教程,您应该已经熟悉了Mojo::服务器::Morbo.

Mojo::服务器::Morbo+-Mojo::服务器::守护进程

它基本上是一个重新启动器Mojo::服务器::守护进程每当项目中的文件发生更改时,都应使用web服务器,因此只应在开发期间使用。要使用它启动应用程序,可以使用莫博脚本。

$莫博/脚本/my_appWeb应用程序位于http://127.0.0.1:3000

容器

有很多方法可以实现云计算Mojolicious公司。为了让您开始将web应用程序容器化,我们将在本食谱中探索其中之一。首先,您需要声明应用程序的CPAN依赖项,例如在生成文件。损益文件。这至少应该包括Mojolicious公司自身。

使用严格;使用警告;使用ExtUtils::MakeMaker;WriteMake文件(版本=>“0.01”,预需求_PM=>{“Mojolicious”=>“8.65”,“Mojolicious::Plugin::Status”=>“1.12”},test=>{TESTS=>'t/*.t'});

helper命令Mojolicious::Command::Author::generate::makefile命令也可以生成最小值生成文件。损益为你。

$ ./myapp.pl生成生成文件...

然后我们需要一个Dockerfile文件描述容器。一个非常简单的就可以了。

来自perl工作目录/opt/myapp复制。运行cpanm--installdeps-n。暴露3000CMD公司/myapp.pl预科

它使用最新的Perl容器从Docker Hub,将应用程序目录的所有内容复制到容器中,使用应用程序::cpanminus,然后在端口上启动应用程序3000使用预先分叉的web服务器。使用Mojolicious::Command::Author::generate::dockerfile命令还有一个helper命令用于生成最小值Dockerfile文件为你。

$ ./myapp.pl生成dockerfile...

要构建和部署我们的容器,还有许多选项可用,这里我们只需使用Docker。

$docker构建-t myapp_image。...$docker运行-d-p 3000:3000--名称myapp_container myapp_image...

现在,您的web应用程序应该作为容器部署在http://127.0.0.1:3000。有关更多信息和更多容器部署选项,我们建议码头工人库伯内特斯文档。

催眠药

催眠药基于Mojo::服务器::Preforkweb服务器,并添加了一些针对高可用性非容器化生产环境特别优化的功能。要使用它启动应用程序,可以使用催眠蟾蜍脚本,在端口上侦听8080,自动守护服务器进程,默认为生产的模式Mojolicious公司Mojolicious::精简应用。

$催眠蟾蜍/脚本/my_app

许多配置设置可以通过Mojolicious中的“config”,有关完整列表,请参阅Mojo::Server::Hypnotoad中的“设置”.

使用Mojolicious::Lite;app->config(hypnodoad=>{listen=>['http://*:80']});get'/'=>{text=>'你好,Wor……HYPNOTOAD万岁!'};应用程序->启动;

或者只需添加催眠蟾蜍部分到您的Mojolicious::插件::配置,Mojolicious::插件::JSONConfigMojolicious::插件::NotYAMLConfig配置文件。

#myapp.conf文件{催眠蟾蜍=>{listen=>[“https://*:443?cert=/etc/server.crt&key=/etc/server.key”],工人=>10}};

但它最大的优点之一是支持轻松的零停机软件升级(热部署)。这意味着您可以升级Mojolicious公司、Perl甚至系统库在运行时都不会停止服务器或丢失单个传入连接,只需再次运行上述命令即可。

$催眠蟾蜍/脚本/my_app正在启动Hypnotoad服务器31841的热部署。

如果您正在使用催眠药在反向代理之后。这允许Mojolicious公司自动拾取X向前-对于X-Forwarded协议标题。

#myapp.conf文件{催眠蟾蜍=>{proxy=>1}};

管理催眠药使用systemd,您可以使用这样的单元配置文件。

[单位]Description=我的Mojolicios应用程序之后=网络目标【服务】类型=分叉用户=sripid文件=/home/sri/myapp/script/amytoad.pidExecStart=/path/to/amytoad/home/sri/myapp/script/my_appExecReload=/path/to/hypnodoad/home/sri/myapp/script/my_appKillMode=进程[安装]WantedBy=多用户目标

零停机软件升级

催眠药使零停机软件升级(热部署)非常简单,正如您在上面看到的那样,但在支持SO_REUSEPORT公司套接字选项,还有另一种可用于所有内置web服务器的方法。

$ ./script/my_app prefork-P/tmp/first.pid-l http://*:8080?重用=1Web应用程序位于http://127.0.0.1:8080网址

您所要做的就是启动第二个监听同一端口的web服务器,然后优雅地停止第一个web服务器。

$ ./script/my_app prefork-P/tmp/second.pid-l http://*:8080?重用=1Web应用程序位于http://127.0.0.1:8080网址$kill-s TERM`cat/tmp/first.pid`

只需记住,两个web服务器都需要使用重新使用参数。

Nginx公司

目前最流行的设置之一是催眠药在后面Nginx公司反向代理,它甚至支持更新版本中的WebSockets。

上游myapp{服务器127.0.0.1:8080;}服务器{听80;服务器名称本地主机;位置/{代理程序(_P)http://myapp(我的应用程序);代理http版本1.1;proxy_set_header升级$http_Upgrade;proxy_set_header连接“升级”;proxy_set_header主机$Host;$proxy_add_X_Forwarded_f的proxy_set_header X-Forwarded-For;proxy_set_header X-Forwarded-Proto$方案;}}

Apache/mod_proxy

另一个好的反向代理是阿帕奇具有mod_proxy(修改代理),配置看起来与上面的Nginx非常相似。如果您需要WebSocket支持,则会提供新版本mod_proxy_ws隧道.

<虚拟主机*:80>服务器名称本地主机<代理*>要求全部授予</代理>ProxyRequests关闭启用ProxyPreserveHostProxyPass/echo ws://localhost:8080/echo代理通行证/http://localhost:8080/keepalive=打开代理密码反向/http://localhost:8080/RequestHeader设置X-Forwarded-Proto“http”</VirtualHost>

阿帕奇/CGI

CGI公司支持现成的,并且您的Mojolicious公司应用程序将自动检测到它作为CGI公司脚本。但不鼓励在生产环境中使用它,因为CGI公司工作正常,速度很慢,而且许多web服务器都很难正确配置。此外,许多实时web功能,如WebSockets,都不可用。

脚本别名//home/sri/my_app/script/my_aapp/

特使

Mojolicious公司应用程序可以部署在使用特使,例如使用与上面的Apache和Nginx类似的反向代理配置。

static_resources(统计资源):侦听器:-名称:listener0地址:socket_address:{地址:0.0.0.0,端口值:80}过滤器链(_C):-过滤器:-名称:gatession.filters.network.http_connection_managertyped_config(类型_配置):“@type”:type.googleapis.com/gatession.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagercodec_type:自动stat_prefix:索引httproute_config(路由配置):名称:本地路由虚拟主机:-名称:服务域:[“*”]路线:-匹配:前缀:“/”路线:集群:本地服务upgrade_configs(升级配置):-upgrade_type:网络套接字http筛选器(_F):-名称:gatession.filters.http.routertyped_config(类型_配置):集群:-名称:本地服务连接超时:0.25s类型:strict_dnslb_policy:round_robin策略装货分配:群集名称:本地服务端点:-磅端点(_E):-端点:地址:socket_address:{地址:mojo,端口值:8080}

虽然这种配置适用于简单的应用程序,但Envoice的典型用例是将应用程序代理实现为一个“服务网格”,提供高级过滤、负载平衡和可观察性功能,如发行。有关更多示例,请访问特使文件.

PSGI/格子

PSGI公司是Perl web框架和web服务器之间的接口普拉克是一个Perl模块和工具箱,其中包含PSGI公司web服务器的中间件、助手和适配器。PSGI公司普拉克灵感来自Python的WSGI和Ruby的Rack。Mojolicious公司应用程序的部署非常简单普拉克,但请注意,许多实时web功能(如WebSockets)不可用。

$plackup/脚本/my_app

普拉克提供了许多服务器和协议适配器供您选择,例如FCGI公司,uWSGI公司修改器(_perl).

$plackup/script/my_app-s FCGI-l/tmp/myapp.sock

这个MOJO_REVERSE_PROXY公司环境变量可用于启用代理支持,这允许Mojolicious公司自动拾取X向前-对于X-Forwarded协议标题。

$MOJO_REVERSE_PROXY=1个补丁/脚本/my_app

如果较旧的服务器适配器无法正确检测应用程序主目录,您可以简单地使用MOJO_HOME公司环境变量。

$MOJO_HOME=/HOME/sri/my_app plackup/脚本/my_app

不需要.psgi文件文件,只需将服务器适配器指向应用程序脚本,如果检测到存在播放_ENV环境变量。

Plack中间件

包装脚本,如我的应用程序.fcgi是分离部署和应用程序逻辑的好方法。

#!/usr/bin/env补丁-s FCGI使用Plack::Builder;建筑商{启用“偏转器”;要求”/脚本/my_app';};

Mojo::服务器::PSGI可以直接用于在包装器脚本中加载和自定义应用程序。

#!/usr/bin/env补丁-s FCGI使用Mojo::Server::PSGI;使用Plack::Builder;建筑商{启用“偏转器”;my$server=Mojo::server::PSGI->new;$server->load_app('./script/my_app');$server->app->config(foo=>'bar');$服务器->to_psgi_app;};

但您甚至可以在应用程序中正确使用中间件。

使用Mojolicious::Lite签名;使用Plack::Builder;获取“/welcome”=>sub($c){$c->render(text=>“你好,Mojo!”);};建筑商{启用“偏转器”;应用程序->启动;};

正在重写

有时,您可能必须在黑箱环境中部署应用程序,在这种环境中,您不能只更改服务器配置,也不能在传递附加信息的反向代理之后X转发-*标题。在这种情况下,你可以用钩子Mojolicious中的“before_dispatch”重写传入的请求。

#如果设置了“X-Forwarded-HTTPS”标头,则更改方案$app->hook(before_dispatch=>sub($c)){$c->req->url->base->scheme(“http”)如果$c->req->headers->header(“X-Forwarded-HTTPS”);});

由于反向代理通常不会传递有关部署应用程序的路径前缀的信息,因此重写传入请求的基本路径也很常见。这允许Mojolicious::Controller中的“url_for”例如,根据当前环境生成可移植URL。

#在生产模式下,将第一个零件和斜线从路径移动到基本路径$app->hook(before_dispatch=>sub($c)){push@{$c->req->url->base->path->trailing_slash(1)},移位@{$c->req->url->path->leading_slash(0)};})如果$app->mode eq为“生产”;

Mojo::URL对象很容易操作,只需确保URL(foo/bar?baz=雅达)表示路由目标的始终相对于基URL(http://example.com/myapp/),表示应用程序的部署位置。

特定于部署的插件

部署特定的第三方插件,如Mojolicious::插件::SetUserGroup不需要包含在应用程序代码中。稍后也可以通过保留的插件的值Mojolicious公司使用任何一个内置配置插件的应用程序Mojolicious::插件::配置,Mojolicious::插件::JSONConfigMojolicious::插件::NotYAMLConfig.

#myapp.conf文件{插件=>[{SetUserGroup=>{user=>“sri”,group=>“staff”}}]};

应用程序嵌入

有时您可能希望重用Mojolicious公司配置文件、数据库连接或其他脚本的帮助器等应用程序Mojo::服务器基于模拟服务器,您可以只嵌入它们。

使用Mojo::Server;#使用模拟服务器加载应用程序my$server=Mojo::server->new;my$app=$server->load_app('./myapp.pl');#访问完全初始化的应用程序比如@{$app->static->paths};说$app->config->{secretidentity};说$app->dumper({just=>'ahelpertest'});比如$app->build_controller->render_toString(template=>'foo');

插件Mojolicious::插件::Mount使用此功能可以将多个应用程序合并为一个应用程序并一起部署。

使用Mojolicious::Lite;app->config(hypnodoad=>{listen=>['http://*:80']});插件安装=>{“test1.example.com”=>“/home/sri/myapp1.pl”};插件安装=>{“test2.example.com”=>“/home/sri/myapp2.pl”};应用程序->启动;

Web服务器嵌入

您还可以使用Mojo::IOLoop中的“one_tick”嵌入内置web服务器Mojo::服务器::守护进程由于某些原因,无法与新的反应堆后端集成到外部环境中,例如外部事件循环。

使用Mojolicious::Lite;使用Mojo::IOLoop;使用Mojo::Server::Daemon;#正常动作获取'/'=>{text=>'你好,世界!'};#将应用程序连接到web服务器并开始接受连接my$daemon=Mojo::Server::daemon->new(app=>app,listen=>['http://*:8080']);$daemon->启动;#从外部环境中反复调用“one_tick”Mojo::IOLoop->one_tick while 1;

实时WEB

实时web是一系列技术的集合,包括Comet(长轮询)、EventSource和WebSockets,这些技术允许内容在生成后立即推送给具有长期连接的消费者,而不是依赖于更传统的拉取模型。所有内置web服务器都使用非阻塞I/O,并且基于Mojo::IOLoop事件循环,它提供了许多非常强大的功能,允许实时web应用程序扩展到数千个并发客户端连接。

后端web服务

Mojo::用户代理也是基于Mojo::IOLoop事件循环,即使对于高延迟后端web服务,它也不会在使用非阻塞时阻止内置web服务器。

使用Mojolicious::Lite签名;#在MetaCPAN中搜索“mojolicus”获取'/'=>子($c){$c->ua->get('faspi.metapan.org/v1/module/_search?q=mojolicios'=>sub($ua,$tx){$c->render('metacpan',hits=>$tx->result->json->{hits}{hits{);});};应用程序->启动;__数据__@@metapan.html.ep<!DOCTYPE html><html>“mojolicious”的MetaCPAN结果<body>%为我的$hit(@$hits){<p><%=$hit->{_source}{release}%></p>% }</body></html>

传递给的回调Mojo::UserAgent中的“get”将在完成对后端web服务的请求后执行,这称为continuation-passing样式。

同步非阻塞操作

多个非阻塞操作(如并发请求)可以轻松地与承诺和Mojo::Promise中的“all”。您创建Mojo::承诺手动对象或使用类似的方法Mojo::UserAgent中的“get_p”为你创造它们。

使用Mojolicious::Lite签名;使用Mojo::Promise;使用Mojo::URL;#在MetaCPAN中搜索“mojo”和“minion”获取'/'=>子($c){#创造两个承诺my$url=Mojo::url->new('http://fastapi.metacpan.org/v1/module/_search');我的$mojo=$c->ua->getp($url->clone->query({q=>'mojo'}));我的$minion=$c->ua->getp($url->clone->query({q=>'minion'}));#在两个承诺都得到解决后做出响应Mojo::承诺->所有($Mojo,$minion)->然后(sub($mozo,$minio){$c->render(json=>){mojo=>$mojo->[0]->result->json('/hits/hits/0/_source/release'),minion=>$minion->[0]->result->json('/hits/hits/0/_source/release')});})->catch(子($err){$c->reply->异常($err);})->等待;};应用程序->启动;

要手动创建承诺,只需将持续传递样式的API包装在返回承诺的函数中。下面是一个示例Mojo::UserAgent中的“get_p”在内部工作。

使用Mojo::UserAgent;使用Mojo::Promise;#用承诺包装用户代理方法my$ua=Mojo::UserAgent->new;子get_p{my$promise=Mojo::promise->new;$ua->get(@_=>sub($ua,$tx){我的$err=$tx->错误;$promise->解决($tx)if$错误|$err->{code};$promise->reject($err->{message});});返回$promise;}#使用我们的新承诺生成函数获取_('https://mojolicious.org')->然后(sub($tx){说$tx->result->dom->at('title')->text;})->等待;

承诺有三种状态,它们开始于悬而未决的然后你打电话Mojo::Promise中的“resolve”将其转换为完成了,或Mojo::Promise中的“拒绝”将其转换为拒绝.

异步/等待

如果你有未来::AsyncAwait安装后,您可以更容易地使用promise。这个异步等待关键字使用-异步等待的标志Mojo::基础,并使带有承诺的闭包的使用完全是可选的。

使用Mojo::Base-strict,-async_await;

这个异步关键字放在附属的关键字,这意味着这个函数总是返回一个promise。返回的值不是Mojo::承诺对象将自动包装在已解决的承诺中。如果函数中抛出异常,将导致拒绝承诺。

使用Mojo::Base-strict,-async_await;异步子hello_p{return“你好,莫霍!”;}hello_p()->然后(sub{say@_})->等待;

这个等待另一方面,关键字使Perl等待承诺的实现。然后,它返回实现值或抛出异常,并给出拒绝原因。然而,在等待期间,事件循环可以自由执行其他任务,因此不会浪费资源。

使用Mojo::Base-strict,-signatures,-async_await;使用Mojo::UserAgent;使用Mojo::URL;my$ua=Mojo::UserAgent->new;#按顺序搜索MetaCPAN非阻塞多个术语异步子搜索panp($terms){my$cpan=Mojo::URL->new('http://fastapi.metacpan.org/v1/module/_search');my@urls=map{$cpan->clone->query(q=>$_)}@$terms;对于我的$url(@urls){我的$tx=等待$ua->getp($url);说$tx->result->json('/hits/hits/0/source/release');}}search_cpan_p(['mojo','minion'])->等待;

上面的循环按顺序执行所有请求,在发送下一个请求之前等待结果。但您也可以同时执行这些请求,方法如下Mojo::Promise中的“all”在等待结果之前将多项承诺结合起来。

使用Mojo::Base-strict,-signatures,-async_await;使用Mojo::Promise;使用Mojo::UserAgent;使用Mojo::URL;my$ua=Mojo::UserAgent->new;#同时搜索MetaCPAN非阻塞多个术语异步子搜索panp($terms){my$cpan=Mojo::URL->new('http://fastapi.metacpan.org/v1/module/_search');my@urls=map{$cpan->clone->query(q=>$_)}@$terms;my@promises=映射{$ua->getp($_)}@urls;my@results=await-Mojo::Promise->all(@promises);对于我的$result(@results){说$result->[0]->result->json('/hits/hits/0/source/release');}}search_cpan_p(['mojo','minion'])->等待;

所有这些还意味着您可以再次使用普通的Perl异常处理。即使是来自CPAN的许多第三方异常处理模块也能正常工作。

使用Mojo::Base-strict,-async_await;使用Mojo::Promise;#捕获非阻塞异常异步子hello_p{eval{awaitMojo::Promise->reject(“这是一个例外”)};if(my$err=$@){warn“错误:$err”}}hello_p()->等待;

它在Mojolicious公司Mojolicious::精简应用。只需用异步关键字和用法等待等待承诺完成了拒绝.

使用Mojolicious::Lite-签名,-asynch_await;#从两个站点请求非阻塞的HTML标题获取“/”=>异步子($c){my$mojo_tx=等待$c->ua->getp('https://mojolicious.org');我的$mojo_title=$mojo-tx->result->dom->at('title')->文本;my$cpan_tx=等待$c->ua->getp('https://metapan.org');my$cpan_title=$cpan_tx->result->dom->at('title')->text;$c->渲染(json=>{mojo=>$mojo_title,cpan=>$cpan_title});};应用程序->启动;

操作返回的承诺将自动获得默认值Mojolicious公司已附加异常处理程序。这使得再次错过非阻塞异常变得更加困难,即使您忘记了自己处理它。

计时器

事件循环的另一个主要功能计时器是用创建的Mojo::IOLoop中的“计时器”例如,可用于延迟响应的呈现,与睡觉,不会阻止可能同时处理的任何其他请求。

使用Mojolicious::Lite签名;使用Mojo::IOLoop;#等待3秒钟,然后再呈现响应获取'/'=>子($c){Mojo::IOLoop->计时器(3=>sub($IOLoop){$c->render(text=>“延迟3秒!”);});};应用程序->启动;

使用创建的重复计时器Mojo::IOLoop中的“重复出现”功能稍微强一些,但需要手动停止,否则它们会不断被释放。

使用Mojolicious::Lite签名;使用Mojo::IOLoop;#在1秒内数到5获取'/'=>子($c){#启动定期计时器我的$i=1;my$id=Mojo::IOLoop->循环(1=>sub($IOLoop){$c->write_chunk($i);如果$i++==5,则$c->完成;});#停止循环计时器$c->on(finish=>sub($c){Mojo::IOLoop->remove($id)});};应用程序->启动;

计时器没有绑定到特定的请求或连接,甚至可以在启动时创建。

使用Mojolicious::Lite签名;使用Mojo::IOLoop;#每隔10秒在后台检查一次标题my$title='还没有标题。';Mojo::IOLoop->循环(10=>sub($IOLoop){应用程序->ua->get('https://mojolicious.org'=>子($ua,$tx){$title=$tx->result->dom->at('title')->文本;});});#显示当前标题获取'/'=>子($c){$c->render(json=>{title=>$title});};应用程序->启动;

请记住,所有这些非阻塞操作都是协同处理的,所以回调不应该阻塞太长时间。

子流程

您还可以使用使用创建的子流程Mojo::IOLoop中的“子进程”,以在不阻塞事件循环的情况下执行计算开销大的操作。

使用Mojolicious::Lite签名;使用Mojo::IOLoop;#将阻塞事件循环5秒的操作获取'/'=>子($c){Mojo::IOLoop->子进程->run_p(sub{睡眠5;返回'♥', 'Mojolicious';})->然后(sub(@results){$c->render(text=>“I$results[0]$results[1]!”);})->catch(子($err){$c->reply->异常($err);});};应用程序->启动;

传递给的回调Mojo::IOLoop::子进程中的“run_p”将在子进程中执行,而不会阻塞父进程的事件循环。然后,回调的结果将在两个进程之间共享,并在父进程中实现或拒绝承诺。

非阻塞操作中的异常

由于定时器和其他非阻塞操作仅在事件循环中运行,因此在应用程序之外,无法自动捕获和处理回调中抛出的异常。但您可以通过订阅事件来手动处理它们Mojo::Reactor中的“error”或者在回调中捕捉它们。

使用Mojolicious::Lite签名;使用Mojo::IOLoop;#将错误消息转发到应用程序日志Mojo::IOLoop->singleton->reactor->on(错误=>sub($reactor,$err){应用程序->日志->错误($err);});#只记录异常(并且连接超时)获取'/connection_times_out'=>sub($c){Mojo::IOLoop->计时器(2=>sub($IOLoop){die“此请求不会得到响应”;});};#捕获并处理异常获取“/catch_exception”=>sub($c){Mojo::IOLoop->计时器(2=>sub($IOLoop){eval{die“此请求将获得响应”};如果$@;则$c->reply->异常($@);});};应用程序->启动;

将所有错误转换为警告的默认订阅服务器通常由添加Mojo::IOLoop作为后备。

Mojo::IOLoop->singleton->reactor->unsubscribe('error');

在开发期间或对于崩溃更可取的应用程序,您还可以通过删除其所有订阅者来使回调中抛出的每个异常都致命。

WebSocket web服务

WebSocket协议提供了客户端和服务器之间的全双向低延迟通信通道。仅通过订阅以下事件来接收消息Mojo::Transaction::WebSocket中的“消息”具有Mojolicious::Controller中的“on”并将其与Mojolicious::Controller中的“send”.

使用Mojolicious::Lite签名;#带有浏览器端代码的模板获取“/”=>“索引”;#WebSocket回显服务网络套接字“/echo”=>sub($c){#已打开$c->app->log->debug(“WebSocket已打开”);#稍微增加连接的非活动超时$c->activity_timeout(300);#传入消息$c->打开(消息=>sub($c,$msg){$c->send(“回音:$msg”);});#已关闭$c->on(finish=>sub($c,$code,$reason=undef){$c->app->log->debug(“WebSocket关闭,状态为$code”);});};应用程序->启动;__数据__@@索引.html.ep<!DOCTYPE html><html>回声<body><脚本>const ws=新WebSocket('<%=url_for('echo')->to_abs%>');//传入消息ws.onmessage=函数(事件){document.body.innerHTML+=事件数据+'<br/>';};//传出消息ws.onopen=函数(事件){window.setInterval(function(){ws.send('Hello Mojo!')},1000);};</script></body></html>

活动Mojo::Transaction::WebSocket中的“finish”将在WebSocket连接关闭后立即发出。

$c->tx->带压缩;

您可以激活永久消息泄漏压缩Mojo::Transaction::WebSocket中的“with_compression”,这可以带来更好的性能,但也会将每个连接的内存使用量增加高达300KiB。

我的$proto=$c->tx->with_protocols(“v2.proto”,“v1.proto”);

您还可以使用Mojo::Transaction::WebSocket中的“with_protocols”协商子协议。

EventSource web服务

EventSource是一种特殊形式的长轮询,您可以在其中使用Mojolicious::Controller中的“写入”将DOM事件从服务器直接发送到客户端。它是单向的,这意味着您必须使用Ajax请求将数据从客户端发送到服务器,但其优点是基础设施要求低,因为它重用HTTP协议进行传输。

使用Mojolicious::Lite签名;#带有浏览器端代码的模板获取“/”=>“索引”;#日志消息的EventSource获取'/events'=>子($c){#稍微增加连接的非活动超时$c->activity_timeout(300);#更改内容类型并最终确定响应标头$c->res->headers->content_type('text/event-stream');$c->写入;#订阅“消息”事件并将“日志”事件转发到浏览器我的$cb=$c->app->log->on(消息=>sub($log,$level,@lines){$c->write(“事件:日志数据:[$level]@lines\n\n”);});#完成后,再次取消订阅“消息”活动$c->打开(完成=>子($c){$c->app->log->unsubscribe(消息=>$cb);});};应用程序->启动;__数据__@@索引.html.ep<!DOCTYPE html><html><head><title>LiveLog</title></head><body><脚本>const events=new EventSource(“<%=url_for”events“%>”);//订阅“日志”事件events.addEventListener('log',函数(event){document.body.innerHTML+=事件数据+'<br/>';},假);</script></body></html>

活动Mojo::Log中的“消息”将为每个新的日志消息和事件发出Mojo::Transaction中的“finish”就在交易完成后。

流式多部分上传

Mojolicious公司包含一个基于Mojo::EventEmitter,在几乎所有层上都有现成的事件,并且可以将其组合起来解决web开发中的一些最困难的问题。

使用Mojolicious::Lite签名;使用标量::Util qw(弱化);#拦截多部分上传并记录收到的每个块钩子after_build_tx=>sub($tx,$app){#订阅“升级”事件以识别多部分上传削弱$tx;$tx->req->content->on(升级=>sub($single,$multi){除非$tx->req->url->path->包含(“/upload”),否则返回;#订阅“part”活动以找到合适的活动$multi->打开(部分=>子($multi,$single){#订阅部件的“body”事件以确保我们拥有所有标题$single->on(body=>sub($single)){#确保我们有正确的部分并替换“read”事件除非$single->headers->content_disposition=~/example/;否则返回;$single->unsubscribe(“读取”)->on(读取=>sub($single,$bytes){#记录我们收到的每个块的大小$app->log->debug(长度($bytes))。”上传字节数');});});});});};#在DATA部分上传表单获取“/”=>“索引”;#流式多部分上传post“/upload”=>{text=>“上传成功。”};应用程序->启动;__数据__@@索引.html.ep<!DOCTYPE html><html><head><title>流媒体多部分上传</title><body>%=form_for-upload=>(enctype=>“multipart/form-data”)=>开始%=file_field“示例”%=submit_button“上传”%结束</body></html>

更多事件循环

在内部Mojo::IOLoop事件循环可以使用多个反应器后端,电动汽车例如,将在可能的情况下自动使用。这反过来又允许其他事件循环,如任何事件只是为了工作。

使用Mojolicious::Lite签名;使用电动汽车;使用AnyEvent;#等待3秒钟,然后再呈现响应获取'/'=>子($c){我的$w;$w=AE::计时器3,0,sub{$c->render(text=>“延迟3秒!”);undef$w;};};应用程序->启动;

用户代理

当我们说Mojolicious公司是我们真正意义上的web框架Mojo::用户代理内置了功能齐全的HTTP和WebSocket用户代理。

REST web服务

使用以下方法可以轻松地执行请求Mojo::UserAgent中的“get”,并始终导致Mojo::Transaction::HTTP对象,它有许多有用的属性和方法。您可以使用检查连接错误Mojo::Transaction中的“result”,或通过直接访问HTTP请求和响应信息Mojo::Transaction中的“req”Mojo::Transaction中的“res”.

使用Mojo::UserAgent;#请求资源并确保没有连接错误my$ua=Mojo::UserAgent->new;我的$tx=$ua->get('https://docs.mojolicious.org/Mojo'=>{Accept=>'text/plain'});我的$res=$tx->结果;#决定如何处理其表示if($res->is_success){比如$res->body}elsif($res->is_error){说$res->消息}elsif($res->code==301){say$res->headers->location}否则{说“随便…”}

虽然方法类似Mojo::消息::响应中的“is_success”Mojo中的“is_error”::消息::响应作为更复杂的REST客户端的构建块。

Web刮取

从网站上删除信息从来没有这么有趣过。内置HTML/XML解析器Mojo::DOM可通过以下方式访问Mojo::Message中的“dom”并且支持所有对独立解析器有意义的CSS选择器,它可以是一个非常强大的工具,特别是用于测试web应用程序。

使用Mojo::UserAgent;#获取网站my$ua=Mojo::UserAgent->new;my$res=$ua->get('https://docs.mojolicio.org网站')->结果;#提取标题说“标题:”,$res->dom->at('head>Title')->text;#提取标题$res->dom('h1,h2,h3')->每个(sub($dom,$i){说“标题:”,$dom->all_text;});#递归访问所有节点以提取不仅仅是文本对于我的$n($res->dom->descendant_nodes->each){#文本或CDATA节点打印$n->内容,如果$n->键入eq“文本”| |$n->输入eq“cdata”;#还包括图像的替代文本如果$n->键入eq“tag”&&$n->标记eq“img”,则打印$n->{alt};}

有关可用CSS选择器的完整列表,请参阅Mojo::DOM::CSS中的“选择器”.

JSON web服务

目前大多数web服务都基于JSON数据交换格式。这就是为什么Mojolicious公司附带可能最快的pure-Perl实现Mojo::JSON内置,可通过Mojo::Message中的“json”.

使用Mojo::UserAgent;使用Mojo::URL;#新鲜用户代理my$ua=Mojo::UserAgent->new;#搜索MetaCPAN以查找“mojolicious”并列出最新版本my$url=Mojo::url->new('http://fastapi.metacpan.org/v1/release/_sarch');$url->查询({q=>“mojolicious”,sort=>“date:desc”});对于我的$hit(@{$ua->get($url)->result->json->{hits}{hits{}}){说“$hit->{source}{name}($hit->{source{author})”;}

基本身份验证

您只需将用户名和密码添加到URL授权标题将自动生成。

使用Mojo::UserAgent;my$ua=Mojo::UserAgent->new;说$ua->get('https://sri:secret(网址:https://sri:secret)@example.com/hideout’)->结果->正文;

如果您正在使用Mojo::URL要构建URL,请注意,如果对象是stringified,则不会包含userinfo部分。您必须将对象本身传递给Mojo::用户代理或使用Mojo::URL中的“to_unsafe_string”.

使用Mojo::UserAgent;使用Mojo::URL;my$ua=Mojo::UserAgent->new;my$url=Mojo::url->new('https://example.com/hideout')->用户信息('sri:secret');说$ua->get($url)->result->body;

装饰跟进请求

Mojo::用户代理可以自动遵循重定向,事件Mojo::UserAgent中的“启动”允许您在初始化每个事务之后以及连接与它们关联之前直接访问它们。

使用Mojo::UserAgent;#用户代理最多跟踪10个重定向my$ua=Mojo::UserAgent->new(max_redirects=>10);#为每个请求添加一个诙谐的标题$ua->打开(开始=>sub($ua,$tx){$tx->req->headers->header(“X-Bender”=>“咬我闪亮的金属屁股!”);说“请求:”,$tx->req->url->clone->to_abs;});#最有可能重定向的请求说'标题:',$ua->get('google.com')->result->dom->at('head>Title')->文本;

这甚至适用于代理连接请求。

内容生成器

内容生成器可以注册到Mojo::UserAgent::Transactor中的“add_generator”为多个请求重复生成相同类型的内容。

使用Mojo::UserAgent;使用Mojo::Asset::File;#添加“流”生成器my$ua=Mojo::UserAgent->new;$ua->transactor->add_generator(流=>子($transactor,$tx,$path){$tx->req->content->asset(Mojo::asset::File->new(path=>$path));});#通过PUT和POST发送多个文件流$ua->put(')http://example.com/upload'=>流=>'/home/sri/mojo.png');$ua->帖子('http://example.com/upload'=>流=>'/home/sri/minion.png');

这个杰森,形式多部分内容生成器始终可用。

使用Mojo::UserAgent;#通过PATCH发送“application/json”内容my$ua=Mojo::UserAgent->new;我的$tx=$ua->补丁('http://api.example.com'=>json=>{foo=>'bar'});#通过GET发送查询参数我的$tx2=$ua->get('search.example.com'=>form=>{q=>'test'});#通过POST发送“application/x-www-form-urlencoded”内容我的$tx3=$ua->帖子('http://search.example.com'=>形式=>{q=>“测试”});#通过PUT发送“多部分/表单数据”内容我的$tx4=$ua->put('upload.example.com'=>form=>{test=>{content=>'Hello World!'}});#通过PUT发送自定义多部分内容my$tx5=$ua->put('api.example.com'=>multipart=>['Hello','World!']);

有关可用内容生成器的更多信息,请参见Mojo::UserAgent::Transactor中的“tx”.

大文件下载

使用下载大文件时Mojo::用户代理你根本不必担心内存的使用,因为它会自动将250KiB以上的所有内容流式传输到一个临时文件中,然后可以使用Mojo::Message中的“save_to”.

使用Mojo::UserAgent;#获取最新Mojolicious tarballmy$ua=Mojo::UserAgent->new(max_redirects=>5);我的$tx=$ua->get('https://www.github.com/mojolicio/mojo/tarball/main(网址:https://www.github.com/mojolicio/mojo/tarball/main)');$tx->result->save_to('mojo.tar.gz');

为了保护您免受过大文件的影响,默认情况下还有2GiB的限制,您可以使用属性进行调整Mojo::UserAgent中的“max_response_size”.

#将限制增加到10GiB$ua->max_response_size(10737418240);

大文件上传

上传一个大文件更容易。

使用Mojo::UserAgent;#通过POST和“multipart/form-data”上传文件my$ua=Mojo::UserAgent->new;$ua->post('example.com/upload'=>form=>{image=>{file=>'/home/sri/hello.png'}});

再一次,您不必担心内存使用情况,所有数据都将直接从文件流式传输。

流媒体响应

在大多数HTTP客户端中,接收流式响应可能非常棘手,但Mojo::用户代理这实际上很容易。

使用Mojo::UserAgent;#接受不确定大小的响应my$ua=Mojo::UserAgent->new(max_response_size=>0);#构建正常事务my$tx=$ua->build_tx(GET=>'http://example.com');#替换“read”事件以禁用默认内容分析器$tx->res->content->unsubscribe('read')->on(read=>sub($content,$bytes){说“流媒体:$bytes”;});#处理交易记录$tx=$ua->开始($tx);

活动Mojo::Content中的“read”将为接收到的每个数据块发出,即使是分块传输编码和gzip内容编码也将在必要时透明处理。

流媒体请求

发送流媒体请求几乎同样简单。

使用Mojo::UserAgent;#构建正常事务my$ua=Mojo::UserAgent->new;my$tx=$ua->build_tx(POST=>'http://example.com');#准备车身my$body=“你好,世界!”;$tx->req->headers->content_length(长度$body);#使用drain回调直接开始写入my$drain=sub($content){my$chunk=substr$body,0,1,'';$content->write($chunk,length$body?__SUB__:undef);};$tx->req->content->$dream;#处理交易记录$tx=$ua->开始($tx);

传递给的排出回调Mojo::Content中的“写入”将在实际写入之前的整个数据块时执行。

非阻塞

Mojo::用户代理已经从头开始设计为非阻塞的,整个阻塞API只是一个简单的方便包装器。特别是对于像web爬行这样的高延迟任务,这可能非常有用,因为您可以同时保持多个并发连接处于活动状态。

使用Mojo::UserAgent;使用Mojo::IOLoop;#并发非阻塞请求my$ua=Mojo::UserAgent->new;$ua->get('https://metapan.org/search?q=mojo'=>sub($ua,$mojo){说$mojo->result->dom->at('title')->text;});$ua->get('https://metacpan.org/search?q=minion'=>sub($ua,$minion){说$minion->result->dom->at('title')->text;});#必要时启动事件循环除非Mojo::IOLoop->is_running,否则Mojo::IOLoop->启动;

但不要试图同时打开到一台服务器的太多连接,否则可能会被淹没。最好使用队列以较小的批处理请求。

使用Mojo::Promise;使用Mojo::UserAgent;我的@urls=('https://docs.mojolicious.org/Mojo/DOM网站',  'https://docs.mojolicious.org/Mojo','https://docs.mojolicious.org/Mojo/文件', 'https://docs.mojolicious.org/Mojo/URL');#具有自定义名称的用户代理,最多可进行5次重定向my$ua=Mojo::UserAgent->new(max_redirects=>5);$ua->事务处理程序->名称(“MyParallelCrawler 1.0”);#使用promise保持事件循环运行,直到我们完成为止my$promise=Mojo::promise->new;我的$count=0;my$fetch=订阅{#如果没有更多URL,则停止除非我的$url=shift@urls;否则返回;#获取下一个标题$ua->get($url=>sub($ua,$tx){说“$url:”,$tx->result->dom->at('title')->text;#下一个请求__SUB__->();$promise->resolve if--$count==0;});$count++;};#一次处理两个请求1的$fetch->()。。2;$promise->wait;

强烈建议尊重每个网站robots.txt(机器人.txt)文件以及服务条款,并在重新打开与同一主机的连接之前等待一段时间,否则运营商可能会被迫阻止您的访问。

并发阻塞请求

你可能已经看到了Mojo::Promise中的“等待”在上面的一些例子中已经有了。它用于使非阻塞操作可移植,允许它们在已经运行的事件循环中工作或按需启动。

使用Mojo::UserAgent;使用Mojo::Promise;#将非阻塞请求与承诺同步my$ua=Mojo::UserAgent->new;我的$mojo_promise=$ua->get_p('https://metapan.org/search?q=mojo');我的$minion_promise=$ua->get_p('https://metacpan.org/search?q=minion');Mojo::Promise->all($Mojo_Promise,$minion_Promise->then(sub($moho,$minion)){说$mojo->[0]->result->dom->at('title')->text;说$minion->[0]->result->dom->at('title')->text;})->等待;

Web套接字

WebSockets不仅适用于服务器端,您可以使用Mojo::UserAgent中的“websocket_p”打开总是非阻塞的新连接。WebSocket握手使用HTTP,这是正常的GET(获取)带有一些附加标头的请求。它甚至可以包含cookie,后面是一个101来自服务器的响应,通知我们的用户代理连接已经建立,可以开始使用双向WebSocket协议。

使用Mojo::UserAgent;使用Mojo::Promise;#打开WebSocket以返回服务my$ua=Mojo::UserAgent->new;$ua->websocket_p('wss://ws.postman-echo.com/raw')->然后(sub($tx){#准备后续承诺,以便我们可以等待消息my$promise=Mojo::promise->new;#等待WebSocket关闭$tx->打开(完成=>sub($tx,$code,$reason){说“WebSocket关闭,状态为$code。”;$promise->resolve;});#收到一条消息后关闭WebSocket$tx->打开(消息=>sub($tx,$msg){说出“WebSocket消息:$msg”;$tx->完成;});#向服务器发送消息$tx->send(“你好!”);#将新承诺插入承诺链返回$promise;})->catch(子($err){#处理失败的WebSocket握手和其他异常警告“WebSocket错误:$err”;})->等待;

UNIX域套接字

不仅支持TCP/IP套接字,还支持UNIX域套接字。在用于进程间通信时,这些套接字具有显著的安全性和性能优势。而不是网址://工作集://你可以使用http+unix://ws-unix操作系统://方案,并沿百分比编码路径传递(/成为%2楼)而不是主机名。

使用Mojo::UserAgent;使用Mojo::Promise;#通过UNIX域套接字“/tmp/foo.sock”获取请求my$ua=Mojo::UserAgent->new;说$ua->get('http+unix://%2Ftmp%2Ffoo.sock/index.html’)->result->body;#通过UNIX域套接字“/tmp/bar.sock”使用HOST头获取请求my$tx=$ua->get('http+unix://%2Ftmp%2Fbar.sock'=>{Host=>'example.com'});说$tx->result->body;#通过UNIX域套接字“/tmp/baz.sock”进行WebSocket连接$ua->websocket_p('ws+unix://%2Ftmp%2Fbaz.sock/echo')->然后(sub($tx){my$promise=Mojo::promise->new;$tx->on(finish=>sub($tx){$promise->resolve});$tx->打开(消息=>sub($tx,$msg){说出“WebSocket消息:$msg”;$tx->完成;});$tx->send(“你好!”);返回$promise;})->catch(子($err){警告“WebSocket错误:$err”;})->等待;

您可以设置主机手动传递主机名。

命令行

你不讨厌从命令行检查巨大的HTML文件吗?多亏了命令Mojolicious::Command::get这种情况即将改变。您可以从中选择与CSS选择器实际相关的部分Mojo::DOM和JSON指针Mojo::JSON::指针.

$mojo获取https://mojolicious.org'标题>标题'

所有id属性的列表怎么样?

$mojo获取https://mojolicious.org“*”属性id

还是所有标题标记的文本内容?

$mojo获取https://mojolicious.org“h1,h2,h3”文本

也许只是第三个标题的文本?

$mojo获取https://mojolicious.org'h1,h2,h3'3文本

您还可以从嵌套的子元素中提取所有文本。

$mojo获取https://mojolicious.org'#mojobar'全部

也可以定制请求。

$mojo get-M POST-H’X-Bender:咬我闪亮的金属屁股!”http://google.com

通过重定向存储响应数据STDOUT公司.

$mojo-get-mojolicious.org>example.html

通过重定向传递请求数据标准DIN.

$mojo get-M PUT mojolicious.org<example.html

或者使用其他程序的输出。

$echo“Hello World”| mojo get-M PUThttps://mojolicious.org

提交表单为应用程序/x-www-form-urlencoded内容。

$mojo get-M POST-f’q=mojo’-f’size=5'https://metapan.org/search网站

并将文件上传为多部分/表单数据内容。

$mojo get-M POST-f'upload=@example.html'mojolicious.org

您可以遵循重定向并查看所有邮件的标题。

$mojo get-r-vhttp://google.com'标题>标题'

只从JSON数据结构中提取您真正需要的信息。

$mojo获取https://fastapi.metacpan.org/v1/author/SRI/名称

这是测试应用程序的一个非常有用的工具。

$ ./myapp.pl get/welcome“head>title”

单线

对于快速破解,尤其是测试,ojo公司单线游戏也是一个不错的选择。

$perl-Mojo-E'说g(“mojolicious.org”)->dom->at(“title”)->文本'

应用

有趣Mojolicious公司适用于所有场合的应用程序黑客攻击。

基本身份验证

基本身份验证数据将自动从授权收割台。

使用Mojolicious::Lite签名;使用Mojo::Util qw(secure_compare);获取'/'=>子($c){#检查用户名“Bender”和密码“rocks”如果secure_compare$c->req->url->to_abs->userinfo,“Bender:rocks”,则返回$c->render(text=>'Hello Bender!');#需要身份验证$c->res->headers->www_authenticate('Basic');$c->render(text=>“需要身份验证!”,status=>401);};应用程序->启动;

这可以与TLS相结合,以实现安全的身份验证机制。

$ ./myapp.pl守护进程-l'https://*:3000?证书=/server.crt&key=/server.key“

添加配置文件

向应用程序添加配置文件就像将文件添加到其主目录并加载插件一样简单Mojolicious::插件::配置。默认名称基于的值Mojolicious中的“绰号”(我的应用程序),附加了.conf文件延伸(我的应用程序配置文件).

$mkdir我的应用程序$cd我的应用程序$touch myapp.pl$chmod 744 myapp.pl(美元)$echo'{name=>“我的Mojolicious应用程序”};'>我的应用程序配置文件

配置文件本身只是一些Perl脚本,它们返回一个带有您选择的配置设置的散列引用。所有这些设置都可以通过该方法使用Mojolicious中的“config”和助手Mojolicious::Plugin::DefaultHelpers中的“config”.

使用Mojolicious::Lite;插件“Config”;my$name=app->config('name');app->log->debug(“欢迎使用$name”);获取'/'=>'with_config';应用程序->启动;__数据__@@使用_config.html.ep<!DOCTYPE html><html><head><title><%=config“name”%></title></head><body>欢迎使用<%=config“name”%></body></html>

或者,您也可以使用JSON格式的配置文件Mojolicious::插件::JSONConfig.

向应用程序添加插件

为了更好地组织代码,并防止助手弄乱应用程序,您可以使用特定于应用程序的插件。

$mkdir-p库/MyApp/Plugin$touch lib/MyApp/Plugin/MyHelpers.pm

它们就像普通插件一样工作,也是的子类Mojolicious::插件。带有基于插件名称前缀的嵌套帮助程序是避免冲突的简单方法。

程序包MyApp::Plugin::MyHelpers;使用Mojo::Base“Mojolicious::Plugin”,-signatures;子寄存器($self、$app、$conf){$app->helper('my_helpers.render_with_header'=>sub($c,@args){$c->res->headers->header('X-Mojo'=>'I<3 Mojolicious!');$c->render(@args);});}1;

您可以拥有任意多个特定于应用程序的插件,与普通插件的唯一区别是您可以使用它们的完整类名加载它们。

使用Mojolicious::Lite签名;使用lib-qw(lib);插件“MyApp::plugin::MyHelpers”;获取'/'=>子($c){$c->my_helpers->render_with_header(text=>'I“莫名其妙!”);};应用程序->启动;

当然,这些插件可以包含不仅仅是帮助程序,请看Mojolicious::PLUGINS中的“PLUGINS”为了一些想法。

向Mojolicious添加命令

到目前为止,您可能已经使用了中描述的许多内置命令Mojolicious::命令,但您知道吗,您可以只添加新的,如果它们位于@INC公司?

软件包Mojolicious::Command::spy;使用Mojo::Base“Mojolicious::Command”,-signatures;has description=>“监视应用程序”;具有用法=>“用法:APPLICATION spy[TARGET]\n”;子运行($self,@args){#泄露机密密码if($args[0]eq'secrets'){比如@{$self->app->secrets}}#泄漏模式elsif($args[0]eq“模式”){说$self->app->mode}}1;

命令行参数直接传递,中有许多有用的属性和方法Mojolicious::命令你可以使用或超载。

$mojo间谍秘密你好世界$ ./script/myapp间谍机密秒3t

要使您的命令特定于应用程序,只需将自定义命名空间添加到Mojolicious::Commands中的“名称空间”并使用类名称,如MyApp::命令::间谍而不是Mojolicious::Command::spy.

#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#添加另一个命名空间以从中加载命令push@{$self->commands->namespaces},'MyApp::Command';}1;

选项-小时/--帮助,--家-米/--模式由自动处理Mojolicious::命令和由所有命令共享。

$ ./script/myapp-spy-m生产模式生产

有关共享选项的完整列表,请参见Mojolicious::Commands中的“SYNOPSIS”.

针对应用程序运行代码

有没有想过与你的Mojolicious公司应用程序进行测试?多亏了命令Mojolicious::命令::eval您可以这样做,应用程序对象本身可以通过应用程序.

$mojo生成lite-app myapp.pl$ ./myapp.pl eval“say for@{app->static->paths}”$ ./myapp.pl eval“say for sort keys%{app->renderer->helpers}”

这个冗长的选项将自动将返回值或返回的数据结构打印到STDOUT公司.

$ ./myapp.pl eval-v“应用->静态->路径->[0]”$ ./myapp.pl eval-V“应用->静态->路径”

使应用程序可安装

曾经想过释放你的Mojolicious公司申请CPAN?事实上,这比你想象的要容易得多。

$mojo生成应用程序MyApp$cd我的应用程序$mv公共库/MyApp/$mv模板库/MyApp/

诀窍是移动公众的模板目录,以便自动安装模块。另外,从Mojolicious::命令::作者安装的应用程序通常不需要命名空间,因此可以将其排除在外。

#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;使用Mojo::File qw(curfile);使用Mojo::Home;#每个CPAN模块都需要一个版本我们的$VERSION=“1.0”;子启动($self){#切换到可安装的主目录$self->home(Mojo::home->new(curfile->sibling('MyApp'));#切换到可安装的“公共”目录$self->static->paths->[0]=$self->home->child(“public”);#切换到可安装的“模板”目录$self->renderer->paths->[0]=$self->home->child(“模板”);#排除作者命令$self->commands->namespaces(['Mojolicious::Command']);我的$r=$self->路线;$r->get('/')->to('example#welcome');}1;

最后,只需对应用程序脚本进行一个小的更改。shebang线成为推荐线#!perl语言,工具链可以在安装期间重写为正确的shebang。

#!perl语言使用严格;使用警告;使用Mojo::File qw(curfile);使用lib curfile->dirname->sibling('lib')->to_string;使用Mojolicious::Commands;#启动应用程序的命令行界面Mojolicious::Commands->start_app('MyApp');

这就是一切,现在您可以像任何其他CPAN模块一样打包应用程序。

$ ./script/my_app生成生成文件$perl生成文件。损益$make测试$make清单$make发行

如果您有一个PAUSE帐户(可以在http://pause.perl.org)甚至上传它。

$mojo cpanify-u USER-p传递MyApp-0.01.tar.gz

代理

虽然每隔Mojolicious公司应用程序具有内置的用户代理Mojolicious::Plugin::DefaultHelpers中的“ua”对于您执行对后端web服务的请求,这并不总是最有效的解决方案。专用代理助手Mojolicious::Plugin::DefaultHelpers中的“proxy->get_p”Mojolicious::Plugin::DefaultHelpers中的“proxy->start_p”一旦从后端web服务接收到新的数据块,就可以将响应内容直接流式传输到客户端。此外,他们还将负责移除逐跳收割台,并自动保护您免受背压问题的影响。如果与后端web服务的连接速度快于与客户端的连接,并且需要限制数据转发,则可能会发生这种情况。最棒的是,一切都是非阻塞的,这意味着您的web服务器可以在等待I/O的同时并发处理其他请求。

使用Mojolicious::Lite签名;#只需转发回复获取'/'=>子($c){$c->proxy->get_p('https://mojolicious.org')->捕获(子($err){$c->log->error(“代理错误:$err”);$c->render(text=>“无法连接到后端web服务!”,状态=>400);});};#转发响应并定制一些内容获取'/*docs'=>sub($c){#自定义请求my$tx=$c->ua->build_tx(GET=>'https://docs.mojolicio.org网站');我的$docs=$c->param('docs');$tx->req->url->path(“/$docs”);$tx->req->headers->user_agent('MojoProxy/1.0');#启动非阻塞请求$c->proxy->start_p($tx)->catch(sub($err)){$c->log->error(“代理错误:$err”);$c->render(text=>“无法连接到后端web服务!”,状态=>400);});#自定义响应$tx->res->content->once(body=>sub($content){$c->res->headers->server('MojoProxy/1.0');});};应用程序->启动;

所有代理助手都返回Mojo::承诺对象,该对象应用于优雅地处理与后端web服务的连接错误。如果您需要将所有标头从客户端转发到后端web服务,请确保使用Mojo::Headers中的“dehop”删除所有逐跳标头。

#克隆和修改请求标头my$headers=$c->req->headers->clone->dehop;$headers->accept('application/json');my$tx=$c->ua->build_tx(PUT=>'https://mojolicious.org'=>$headers->to_hash);

你好,世界

如果每个字节都重要,那么这是最小的你好,世界您可以使用的应用程序Mojolicious::精简.

使用Mojolicious::Lite;any{text=>“你好,世界!”};应用程序->启动;

它之所以有效,是因为所有没有模式的路由都默认为/即使路由器没有执行任何实际代码,也可以进行自动呈现。渲染器只会拾取文本值,并生成响应。

Hello World单线游戏

这个你好,世界上面的示例在ojo公司单衬里。

$perl-Mojo-E'a({text=>“Hello World!”})->start'守护进程

您可以使用中的所有命令Mojolicious::命令.

$perl-Mojo-E'a({text=>“Hello World!”})->start'get-v/

更多

您可以继续Mojolicious::指南现在或者看看Mojolicious维基,其中包含许多不同作者编写的更多文档和示例。

支持

如果您有任何文档可能还没有回答的问题,请毫不犹豫地在论坛、或上IRC公司.