=编码utf8=头1名称Mojolicus::指南::食谱-使用Mojolicus烹饪=标题1概述本文档包含许多有趣的L烹饪食谱.=头1概念每升基本装备开发人员应该知道。=头部2阻塞和非阻塞操作A我操作是一个子例程,它阻止调用子例程的执行,直到子例程已完成。子foo{my$result=块子例程();...}A我另一方面,操作允许调用子例程继续执行,即使子例程尚未完成。调用子例程不等待,而是传递一个回调子程序完成了,这称为继续传递样式。子foo{非阻塞子例程(sub($result){...});...}而L已从头开始为非阻塞I/O和事件循环设计,不可能神奇地使Perl代码非阻塞。您必须使用通过以下模块提供的专用非阻塞代码L(左)和L或第三方事件循环。您可以将阻塞代码封装在L(左)尽管这样可以防止它干扰您的非阻塞代码。=head2事件循环事件循环基本上是一个不断测试外部事件并执行适当回调的循环处理它们时,它通常是程序中的主循环。文件描述符可读性/可写性的非阻塞测试计时器是高度可伸缩的网络服务器常用的事件,因为它们允许单个进程处理并发数千个客户端连接。而(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(@过期);}在L中该事件循环为L.=head2反向代理反向代理体系结构是一种在许多生产环境中使用的部署技术,其中I服务器放在应用程序前面,充当外部客户端可访问的端点。它可以提供很多优点,如从外部终止SSL连接,将并发打开的套接字数量限制为Mojolicious应用程序(甚至使用Unix套接字),跨多个实例平衡负载,或支持多个应用程序通过同一IP/端口。..........................................: :+--------+ : +-----------+ +---------------+ :| |-------->| | | | :|client|:|reverse|----->|Mojolicious|:||<---------|proxy||应用程序|:+--------+ : | |<-----| | :: +-----------+ +---------------+ :: :..系统边界(例如同一主机)。。。。。。但是,这种设置引入了一些问题:应用程序将接收来自反向代理的请求,而不是原始客户;应用程序内部的地址/主机名与从外部可见;如果终止SSL,反向代理将通过HTTPS公开服务,同时将HTTP用于Mojolicious应用程序。例如,比较来自客户端的示例请求和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有用)和URL通过L生成将如下所示:http://10.20.30.40/bar/2而不是像这样对客户有意义的事情:https://api.example.com/bar/2为了解决这些问题,您可以配置反向代理来发送丢失的数据(请参阅LL(左))并通过设置环境变量C告诉您的应用程序.在更复杂的情况下,通常涉及多个代理或位于网络外部的代理,它可以是需要通过设置C来告诉应用程序从哪个ip地址期望代理请求以逗号分隔的地址或CIDR网络列表。为了进行更精细的控制,L包括如何这些更改可以手动实现。=头1部署获取L和L在不同平台上运行的应用程序。请注意,许多实时web功能基于L事件循环,因此需要一个内置的web服务器能够充分发挥他们的潜力。=head2内置web服务器L(左)包含一个非常可移植的非阻塞I/O HTTP和带有L的WebSocket服务器。它是通常在开发和构建更高级的web服务器时使用,但它足够稳定和快速中小型应用程序。$ ./script/my_app守护程序Web应用程序位于http://127.0.0.1:3000每个应用程序都可以通过命令L使用它,具有多种配置选项,并且众所周知,Perl使用其单进程体系结构在每个平台上工作。$ ./script/my_app守护程序-h…可用选项列表。。。另一个巨大的优势是它支持TLS和WebSockets,即开即用,这是一种用于测试的开发证书目的是内置的,所以它可以正常工作,但您可以指定支持的所有侦听位置L(左).$ ./script/my_app守护进程-l https://[::]:3000Web应用程序位于https://[::]:3000要使用systemd管理web服务器,可以使用这样的单元配置文件。[单位]Description=我的Mojolicios应用程序之后=网络目标[服务]类型=简单用户=sriExecStart=/home/sri/myapp/script/my_app守护进程-m production-l http://*:8080[安装]WantedBy=多用户目标=head2前移对于更大的应用程序L包含UNIX优化的预分叉web服务器L,它可以利用多个CPU内核和复制-写入内存管理,扩展到数千个并发客户端连接。Mojo::服务器::Prefork|-Mojo::服务器::守护程序[1]|-Mojo::服务器::守护进程[2]|-Mojo::服务器::守护进程[3]+-Mojo::服务器::守护程序[4]它基于L并通过命令对每个应用程序可用L(左).$ ./脚本/my_app预处理Web应用程序位于http://127.0.0.1:3000由于所有内置web服务器都基于L事件循环,它们可以通过非阻塞进行最佳扩展操作。但是,如果您的应用程序出于某种原因需要执行许多阻塞操作,您可以改进通过增加工作进程数和减少每个进程的并发连接数来提高性能允许工人操作(通常低至C<1>)。$ ./script/my_app预处理-m生产-w 10-c 1Web应用程序位于http://127.0.0.1:3000在启动期间,您的应用程序被预加载到管理器进程中,该进程不运行事件循环,因此您可以使用L(左)每当新的工作进程被分叉并启动其事件循环时运行代码。使用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=多用户目标=头2莫尔博读取L后,你应该已经熟悉L了.Mojo::服务器::Morbo+-Mojo::服务器::守护进程它基本上是一个重新启动器,用于分叉一个新的L每当项目中有文件时,web服务器更改,因此只应在开发期间使用。要使用它启动应用程序,可以使用L脚本。$莫博/脚本/my_appWeb应用程序位于http://127.0.0.1:3000=头部2容器有很多方法可以使用L实现云阴性。开始将web应用程序容器化我们将在这个食谱中探索其中之一。首先,您需要声明应用程序的CPAN依赖项,例如在C中文件。这至少应包括L自身。使用严格;使用警告;使用ExtUtils::MakeMaker;WriteMake文件(版本=>“0.01”,预需求_PM=>{“Mojolicious”=>“8.65”,“Mojolicious::Plugin::Status”=>“1.12”},test=>{TESTS=>'t/*.t'});助手命令L也可以生成最小的C对于你。$ ./myapp.pl生成生成文件...然后我们需要一个C描述容器。一个非常简单的就可以了。来自perl工作目录/opt/myapp复制。运行cpanm--installdeps-n。3000曝光CMD公司/myapp.pl预处理它使用了最新的L从Docker Hub,复制您的将应用程序目录安装到容器中,使用L安装CPAN依赖项,然后启动带有预分叉web服务器的端口C<3000>上的应用程序。带L还有一个helper命令来生成最小的C为你。$ ./myapp.pl生成dockerfile...要构建和部署我们的容器,还有许多选项可用,这里我们只需使用Docker。$docker构建-t myapp_image。...$docker运行-d-p 3000:3000--名称myapp_container myapp_image...现在,您的web应用程序应该部署为C下的容器。有关更多信息和我们推荐更多的容器部署选项L(左)文档。=头部2催眠器L(左)基于Lweb服务器,并添加了一些功能特别针对高可用性非容器化生产环境进行了优化。要用它启动应用程序,您需要可以使用L在端口C<8080>上侦听的脚本会自动对服务器进程进行守护,并使用默认值至CL的模式和L应用。$催眠蟾蜍/脚本/my_app许多配置设置都可以用L从应用程序内部进行调整,总共列表见L.使用Mojolicious::Lite;app->config(催眠蟾蜍=>{listen=>['http://*:80']});get'/'=>{text=>'你好,Wor……HYPNOTOAD万岁!'};应用程序->启动;或者只添加一个CL部分,LL(左)配置文件。#我的应用程序配置文件{催眠蟾蜍=>{listen=>[“https://*:443?cert=/etc/server.crt&key=/etc/server.key”],工人=>10}};但它最大的优点之一是支持轻松的零停机软件升级(热部署)。意味着你可以升级L、Perl甚至系统库在运行时都不会停止服务器或只需再次运行上面的命令,就会丢失一个传入连接。$hypnotoad/脚本/my_app正在启动Hypnoad服务器31841的热部署。如果您正在使用L,您可能还想启用代理支持倒车后代理。这允许L自动拾取C和C标题。#我的应用程序配置文件{催眠蟾蜍=>{proxy=>1}};管理L使用systemd,您可以使用这样的单元配置文件。[单位]Description=我的Mojolicios应用程序之后=网络目标[服务]类型=分叉用户=sripid文件=/home/sri/myapp/script/amytoad.pidExecStart=/path/to/amytoad/home/sri/myapp/script/my_appExecReload=/path/to/amytoad/home/sri/myapp/script/my_appKillMode=进程[安装]WantedBy=多用户目标=head2零停机软件升级L(左)如您所见,使零停机软件升级(热部署)非常简单但在支持C语言的现代操作系统上套接字选项,还有另一种方法适用于所有内置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服务器都需要用C启动参数。=头部2 Nginx现在最流行的设置之一是L在L后面反向代理,它甚至支持更新版本中的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$方案;}}=头2 Apache/mod_proxy另一个好的反向代理是L使用C,配置看起来很不错类似于上面的Nginx。如果您需要WebSocket支持,更新的版本会附带C.服务器名称本地主机要求所有授权ProxyRequests关闭启用ProxyPreserveHostProxyPass/echo ws://localhost:8080/echo代理通行证/http://localhost:8080/keepalive=开代理密码反向/http://localhost:8080/RequestHeader设置X-Forwarded-Proto“http”=头部2 Apache/CGIC类是现成的支持,您的L应用程序将自动检测其执行方式a C类脚本。但不鼓励在生产环境中使用它,因为C有效,它速度非常慢,而且许多web服务器使得正确配置变得异常困难。此外,许多实时web功能(如WebSockets)不可用。脚本别名//home/sri/my_app/script/my_aapp/=head2特使L(左)应用程序可以部署在使用L,例如,使用与上面的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_过滤器:-名称:gatession.filters.http.routertyped_config(类型_配置):集群:-名称:本地服务连接超时:0.25s类型:strict_dnslb_policy:round_robin(磅策略)加载分配(_A):集群名称:本地服务端点:-磅端点(_E):-端点:地址:socket_address:{地址:mojo,端口值:8080}虽然此配置适用于简单的应用程序,但Envoice的典型用例是实现以下代理应用程序作为“服务网格”提供高级过滤、负载平衡和可观察性功能,例如见L。有关更多示例,请访问L(左).=头部2 PSGI/PlackL(左)是Perl web框架和web服务器之间的接口是一个Perl模块和工具包包含Lweb服务器的中间件、助手和适配器。L(左)和L灵感来自Python的WSGI和Ruby的Rack。L(左)使用L部署应用程序非常简单但要注意实时web功能(如WebSockets)不可用。$plackup/脚本/my_appL(左)提供了许多服务器和协议适配器供您选择,例如C,C和C.$plackup/script/my_app-s FCGI-l/tmp/myapp.sockC类环境变量可用于启用代理支持,这允许L自动拾取C和C标题。$MOJO_REVERSE_PROXY=1个补丁/脚本/my_app如果较旧的服务器适配器无法正确检测应用程序主目录,您只需使用C类环境变量。$MOJO_HOME=/HOME/sri/my_app plackup/脚本/my_app不需要C<.psgi>文件,只需将服务器适配器指向应用程序脚本,它就会自动如果检测到C的存在,则表现得像一个环境变量。=head2 Plack中间件像C这样的包装脚本是分离部署和应用程序逻辑的好方法。#!/usr/bin/env plackup-s FCGI使用Plack::生成器;建筑商{启用“偏转器”;需要“/脚本/my_app';};L(左)可以直接用于在包装器脚本中加载和自定义应用程序。#!/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!”);};建筑商{启用“偏转器”;应用程序->启动;};=head2重写有时,您可能必须将应用程序部署在黑箱环境中,在这种环境中,您不能只更改服务器配置或在使用C传递附加信息的反向代理后面标题。在这种情况下你可以用钩子L重写传入的请求。#如果设置了“X-Forwarded-HTTPS”标头,则更改方案$app->hook(before_dispatch=>sub($c)){$c->req->url->base->scheme(“https”)如果$c->req->headers->header(“X-Forwarded-HTTPS”);});由于反向代理通常不会传递有关可能部署的应用程序的路径前缀的信息在下,重写传入请求的基本路径也很常见。这允许L(左)例如,根据当前环境生成可移植URL。#在生产模式下,将第一个零件和斜线从路径移动到基本路径$app->hook(before_dispatch=>sub($c)){push@{$c->req->url->base->path->trailing_slash(1)},shift@{$c->req->url->path->leading_slash(0)};})如果$app->mode eq为“生产”;L(左)对象非常容易操作,只需确保URL(C),表示路由目标始终相对于基本URL(C),表示应用程序的部署位置。=head2部署特定插件特定于部署的第三方插件,如L不需要包含在您的应用程序代码。它们也可以稍后通过保留的C加载L的值应用程序使用任何一个内置配置插件L的,L(左)或L.#我的应用程序配置文件{插件=>[{SetUserGroup=>{user=>“sri”,group=>“staff”}}]};=head2应用程序嵌入有时您可能希望重用L的部分配置文件、数据库等应用程序其他脚本的连接或帮助程序,使用这个小L基于模拟服务器,您可以只嵌入它们。使用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');插件L使用此功能可以将多个应用程序合并为一个并一起部署。使用Mojolicious::Lite;app->config(催眠蟾蜍=>{listen=>['http://*:80']});插件安装=>{“test1.example.com”=>“/home/sri/myapp1.pl”};插件安装=>{“test2.example.com”=>“/home/sri/myapp2.pl”};应用程序->启动;=head2 Web服务器嵌入你也可以使用L嵌入内置的web服务器L变成外星人由于某些原因,像外部事件循环这样的环境不能与新的反应堆后端集成。使用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;=head1实时网络实时web是一组技术,包括Comet(长轮询)、EventSource和WebSockets允许在生成内容后立即将内容推送给具有长期连接的用户,而不是依赖于更传统的拉动模型。所有内置web服务器都使用非阻塞I/O,并基于L事件循环,它提供了许多非常强大的功能,允许实时web应用程序扩展到数千个并发客户端连接数。=head2后端web服务自L起也是基于L事件循环,当使用非阻塞,即使对于高延迟后端web服务也是如此。使用Mojolicious::Lite签名;#搜索MetaCPAN以查找“mojolicious”获取“/”=>子($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 “mojolicious”的MetaCPAN结果 %为我的$hit(@$hits){

<%=$hit->{_source}{release}%>

% } 传递给L的回调将在对后端web服务的请求完成后执行完成后,这称为继续传递样式。=head2同步非阻塞操作多个非阻塞操作(如并发请求)可以轻松地与承诺和L(左).您创建L手动对象或使用L等方法为你创造它们。使用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包装在返回承诺的函数中。下面是L的一个示例在内部工作。使用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;})->等待;承诺有三种状态,它们以C开头然后你打电话给L将其转换为C类,或L将它们转换为C.=head2异步/等待如果你有L安装后,您可以更轻松地使用承诺。C类和C关键字是使用L的C<-async_await>标志启用的,并使用带有承诺的闭包完全可选。使用Mojo::Base-strict,-async_await;C类关键字放在C之前关键字,表示此函数始终返回一个promise。返回的值不是L对象将自动包装在已解决的承诺中。如果函数中抛出异常,这将导致拒绝承诺。使用Mojo::Base-strict,-async_await;异步子hello_p{return“你好,莫霍!”;}hello_p()->然后(sub{say@_})->等待;C类另一方面,关键字使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'])->等待;上面的循环按顺序执行所有请求,在发送下一个请求之前等待结果。但你也可以相反,可以使用L等方法并发执行这些请求将多项承诺结合起来在等待结果之前。使用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()->等待;它在L中的工作原理相同和L应用。只需用C类关键字并使用C等待承诺变成C或C.使用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');我的$cpan_title=$cpan-tx->result->dom->at('title')->文本;$c->渲染(json=>{mojo=>$mojo_title,cpan=>$cpan_title});};应用程序->启动;行动返回的承诺将自动获得默认L附加了异常处理程序。让它成为现实即使您忘记自己处理,也很难再次错过非阻塞异常。=头2计时器计时器是事件循环的另一个主要功能,它是用L创建的并且例如可以是用于延迟响应的呈现,与C不同,不会阻止可能处理的任何其他请求同时。使用Mojolicious::Lite签名;使用Mojo::IOLoop;#等待3秒钟,然后再呈现响应获取“/”=>子($c){Mojo::IOLoop->计时器(3=>sub($IOLoop){$c->render(text=>“延迟3秒!”);});};应用程序->启动;使用L创建的循环计时器功能略强,但需要手动停止,否则它们会一直被排放。使用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});};应用程序->启动;只需记住,所有这些非阻塞操作都是协同处理的,因此您的回调不应该阻塞太长了。=head2子流程您还可以使用使用L创建的子流程,执行计算成本高操作而不阻塞事件循环。使用Mojolicious::Lite签名;使用Mojo::IOLoop;#将阻塞事件循环5秒的操作获取“/”=>子($c){Mojo::IOLoop->子流程->运行_ p(子{睡眠5;返回♥', 'Mojolicious';})->然后(sub(@results){$c->render(text=>“I$results[0]$results[1]!”);})->catch(子($err){$c->reply->异常($err);});};应用程序->启动;传递给L的回调将在子进程中执行,而不会阻塞父进程的事件循环。回调的结果将在两个进程之间共享在父流程中实现或拒绝的承诺。=head2非阻塞操作中的异常由于计时器和其他非阻塞操作仅在应用程序外的事件循环中运行,回调中抛出的异常无法自动捕获和处理。但您可以通过以下方式手动处理订阅事件L或者在回调中捕捉它们。使用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->异常($@);});};应用程序->启动;将所有错误转换为警告的默认订阅服务器通常由L添加作为后备。Mojo::IOLoop->singleton->reactor->unsubscribe('error');在开发过程中,或者对于崩溃更可取的应用程序,您还可以生成删除其所有订阅者时引发致命回调。=head2 WebSocket web服务WebSocket协议提供客户端和服务器之间的全双向低延迟通信通道。只需订阅L等事件即可接收消息具有L(左)并用L返回.使用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 回声 事件L将在WebSocket连接完成后立即发出关闭。$c->tx->带压缩;您可以激活C用L压缩,这个可以这样不仅可以获得更好的性能,而且还可以将每个连接的内存使用量增加高达300KiB。我的$proto=$c->tx->with_protocols(“v2.proto”,“v1.proto”);你也可以使用L协商子协议。=head2 EventSource web服务EventSource是一种特殊形式的长轮询,您可以在其中使用L直接发送DOM从服务器到客户端的事件。它是单向的,这意味着您必须使用Ajax请求发送数据然而,从客户端到服务器,其优点是对基础设施的要求较低,因为它重用了HTTP协议用于运输。使用Mojolicious::Lite签名;#带有浏览器端代码的模板获取“/”=>“索引”;#日志消息的EventSource获取“/events”=>sub($c){#稍微增加连接的非活动超时$c->activity_timeout(300);#更改内容类型并最终确定响应标头$c->res->headers->content_type('文本/事件流');$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 实时日志 事件L将针对每个新日志消息和事件L发出就在交易完成后。=head2流媒体多部分上传L(左)包含一个基于L的非常复杂的事件系统,打开现成的事件几乎所有层,可以将其组合起来解决web开发中的一些最困难的问题。使用Mojolicious::Lite签名;使用标量::Util qw(弱化);#拦截多部分上传并记录收到的每个块hook-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 流式多部分上传 %=form_for上传=>(enctype=>“多部分/表单数据”)=>开始%=file_field“示例”%=submit_button“上传”%结束 =head2更多事件循环在内部,L事件循环可以使用多个反应器后端,L例如,将自动如果可能的话使用。这反过来又允许其他事件循环,如L只是为了工作。使用Mojolicious::Lite签名;使用电动汽车;使用AnyEvent;#等待3秒钟,然后再呈现响应获取“/”=>子($c){我的$w;$w=AE::计时器3,0,sub{$c->render(text=>“延迟3秒!”);undef$w;};};应用程序->启动;=头1用户代理当我们说L时是一个web框架,我们实际上是指它,用L有一个功能齐全的HTTP和内置的WebSocket用户代理。=head2 REST web服务使用L等方法可以轻松地执行请求,并始终导致L(左)对象,它有许多有用的属性和方法。您可以检查连接错误带L,或通过直接访问HTTP请求和响应信息L(左)和L.使用Mojo::UserAgent;#请求资源并确保没有连接错误my$ua=Mojo::UserAgent->new;我的$tx=$ua->get('https://docs.mojolicious.org/Mojo'=>{Accept=>'text/plain'});我的$res=$tx->结果;#决定如何处理其表示if($res->issuccess){说$res->主体}elsif($res->is_error){说$res->消息}elsif($res->code==301){say$res->headers->location}否则{说“随便…”}而L等方法和L用作建筑物用于更复杂的REST客户端的块。=头2刮纸从网站上删除信息从来没有这么有趣过。内置HTML/XML解析器L可通过L访问并支持对独立解析器有意义的所有CSS选择器可以是一个非常强大的工具,特别是用于测试web应用程序。使用Mojo::UserAgent;#获取网站my$ua=Mojo::UserAgent->new;my$res=$ua->get('https://docs.mojolicious.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选择器的完整列表,请参阅L.=head2 JSON web服务目前大多数web服务都基于JSON数据交换格式。这就是为什么L随附可能是最快的pure-Perl实现L内置,可通过L(左).使用Mojo::UserAgent;使用Mojo::URL;#新鲜用户代理my$ua=Mojo::UserAgent->new;#搜索MetaCPAN以查找“mojolicious”并列出最新版本my$url=Mojo::url->new('http://fastapi.metacpan.org/v1/release/_search');$url->查询({q=>“mojolicious”,sort=>“date:desc”});对于我的$hit(@{$ua->get($url)->result->json->{hits}{hits{}}){说“$hit->{_source}{name}($hit->{_source}{author})”;}=head2基本身份验证您只需在URL中添加用户名和密码,即C标题将自动生成。使用Mojo::UserAgent;my$ua=Mojo::UserAgent->new;说$ua->get('https://sri:secret@example.com/hideout’)->结果->正文;如果你使用L要构建URL,请注意,如果对象是串起来的。你必须将对象本身传递给L或使用L.使用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;=head2装饰跟进请求L(左)可以自动遵循重定向,事件L允许您直接访问每个事务都是在初始化之后、连接与它们关联之前完成的。使用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')->文本;这甚至适用于代理C请求。=头2内容生成器内容生成器可以注册到L生成相同类型的针对多个请求重复内容。使用Mojo::UserAgent;使用Mojo::资产::文件;#添加“流”生成器my$ua=Mojo::UserAgent->new;$ua->transactor->add_generator(流=>sub($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');C类,C
和C内容生成器始终可用。使用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发送“multipart/form-data”内容我的$tx4=$ua->put('upload.example.com'=>form=>{test=>{content=>'Hello World!'}});#通过PUT发送自定义多部分内容my$tx5=$ua->put('api.example.com'=>multipart=>['Hello','World!']);有关可用内容生成器的更多信息,请参见L.=head2大文件下载用L下载大文件时你根本不必担心内存使用,因为它会自动将高于250KiB的所有内容流式传输到一个临时文件中,然后可以使用L(左).使用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('mo.tar.gz');为了保护您不受过大文件的影响,默认情况下还有2GiB的限制,您可以使用属性L.#将限制增加到10GiB$ua->max_response_size(10737418240);=head2大文件上传上传一个大文件更容易。使用Mojo::UserAgent;#通过POST和“multipart/form-data”上传文件my$ua=Mojo::UserAgent->new;$ua->post('example.com/upload'=>form=>{image=>{file=>'/home/sri/hello.png'}});再一次,您不必担心内存使用情况,所有数据都将直接从文件流式传输。=head2流式处理响应在大多数HTTP客户端中,接收流式响应可能非常棘手,但L让它成为事实容易的。使用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(“读取”)->on(读取=>sub($content,$bytes){说“流媒体:$bytes”;});#处理交易记录$tx=$ua->开始($tx);事件L将针对接收到的每个数据块发出,即使是分块传输如果需要,编码和gzip内容编码将被透明地处理。=head2流式处理请求发送流媒体请求几乎同样简单。使用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);传递给L的drain回调只要前面的整个数据块实际上已经写好了。=头部2非阻塞L(左)已经从头开始设计为非阻塞的,整个阻塞API只是一个简单的方便包装。特别是对于像网络爬行这样的高延迟任务,这可能非常有用,因为您可以同时保持多个并发连接处于活动状态。使用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'=>子($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->新建(max_redirects=>5);$ua->transactor->name('MyParallelCrawler1.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;强烈建议尊重每个站点C文件以及服务条款,并等待在重新打开同一主机的连接之前,操作员可能会被迫阻止您的访问。=head2并发阻塞请求你可能见过L在上面的一些例子中已经有了。它用于进行非阻塞操作可移植,允许它们在已经运行的事件循环中工作或按需启动。使用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;})->等待;=头2 WebSocketsWebSockets不仅适用于服务器端,还可以使用L为了打开新的连接,它们总是非阻塞的。WebSocket握手使用HTTP,并且是一个正常的C请求并附加一些标题。它甚至可以包含cookie,然后是来自服务器的C<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”;})->等待;=头2 UNIX域套接字不仅支持TCP/IP套接字,还支持UNIX域套接字用于进程间通信时,性能会有所提高。代替C和C您可以使用C类和C方案,并沿百分比编码路径传递(C</>变为C<%2F>),而不是主机名。使用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标头的GET请求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”;})->等待;您可以设置C手动传递主机名。=head2命令行你不讨厌从命令行检查巨大的HTML文件吗?多亏了命令L那个即将改变。您可以从L中选择与CSS选择器实际相关的部分和JSON来自L的指针.$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通过重定向C存储响应数据.$mojo-get-mojolicious.org>example.html通过重定向C传递请求数据.$mojo get-M PUT mojolicious.org<example.html或者使用其他程序的输出。$echo“Hello World”| mojo get-M PUThttps://mojolicious.org以C格式提交表单内容。$mojo get-M POST-f’q=mojo’-f’size=5'https://metapan.org/search网站并以C格式上传文件内容。$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”=头2单线对于快速破解,尤其是测试,L单线游戏也是一个不错的选择。$perl-Mojo-E'说g(“mojolicious.org”)->dom->at(“title”)->文本'=头部1应用趣味L适用于所有场合的应用程序黑客攻击。=head2基本身份验证基本身份验证数据将自动从C中提取收割台。使用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“=head2添加配置文件向应用程序添加配置文件就像将文件添加到其主目录并加载插件L。默认名称基于L的值(C)),附加了一个C<.conf>扩展名(C).$mkdir我的应用程序$cd我的应用程序$touch myapp.pl$chmod 744 myapp.pl(美元)$echo'{name=>“我的Mojolicious应用程序”};'>我的应用程序配置文件配置文件本身只是一个Perl脚本,它返回一个带有配置设置的散列引用选择。所有这些设置都可以通过方法L使用和助手L(左).使用Mojolicious::Lite;插件“Config”;my$name=app->config('name');app->log->debug(“欢迎使用$name”);获取'/'=>'with_config';应用程序->启动;__数据__@@使用_config.html.ep <%=配置“名称”%> 欢迎使用<%=config“name”%> 或者,您也可以使用JSON格式的配置文件和L.=head2在应用程序中添加插件为了更好地组织代码并防止助手弄乱应用程序,可以使用特定于应用程序的插件。$mkdir-p库/MyApp/Plugin$touch库/MyApp/Plugin/MyHelpers.pm它们就像普通插件一样工作,也是L的子类。带有前缀的嵌套帮助程序基于插件名称是避免冲突的简单方法。程序包MyApp::Plugin::MyHelpers;使用Mojo::Base“Mojolicious::Plugin”,-signatures;子寄存器($self、$app、$conf){$app->helper('my_helpers.render_with_header'=>子($c,@args){$c->res->headers->headers('X-Mojo'=>'I<3 Mojolicus!');$c->render(@args);});}1;您可以有任意多个特定于应用程序的插件,与普通插件的唯一区别是您可以加载他们使用全名。使用Mojolicious::Lite签名;使用lib-qw(lib);插件“MyApp::plugin::MyHelpers”;获取“/”=>子($c){$c->my_helpers->render_with_header(text=>'I莫乔利奇!”);};应用程序->启动;当然,这些插件可以包含不仅仅是帮助程序,看看L为数不多思想。=head2向Mojolicious添加命令到目前为止,您可能已经使用了L中描述的许多内置命令,但你知道吗您可以只添加新的,如果需要,它们将由命令行界面自动拾取放置在C<@INC>的目录中?软件包Mojolicious::Command::spy;使用Mojo::Base“Mojolicious::Command”,-signatures;has description=>“监视应用程序”;has usage=>“用法:APPLICATION spy[TARGET]\n”;子运行($self,@args){#泄露机密密码if($args[0]eq“机密”){表示@{$self->app->secrets}}#泄漏模式elsif($args[0]eq“模式”){说$self->app->mode}}1;命令行参数直接传递,中有许多有用的属性和方法L(左)你可以使用或超载。$mojo间谍秘密你好世界$ ./script/myapp间谍机密秒3t要使您的命令特定于应用程序,只需将自定义名称空间添加到L并使用类似C的类名而不是C.#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#添加另一个命名空间以从中加载命令push@{$self->commands->namespaces},'MyApp::Command';}1;选项C<-h>/C<--help>、C<--home>和C<-m>/C<--mode>由L自动处理由所有命令共享。$ ./script/myapp-spy-m生产模式生产有关共享选项的完整列表,请参阅L.=head2针对应用程序运行代码曾经想过对你的L进行一次快速的单打应用程序来测试某些东西?多亏了命令L您可以这样做,应用程序对象本身可以通过C访问.$mojo生成lite-app myapp.pl$ ./myapp.pl eval“say for@{app->static->paths}”$ ./myapp.pl eval“say for sort keys%{app->renderer->helpers}”C类选项将自动将返回值或返回的数据结构打印到C.$ ./myapp.pl eval-v“应用->静态->路径->[0]”$ ./myapp.pl eval-V“应用->静态->路径”=head2使应用程序可安装曾经想过释放你的L申请CPAN?这实际上比你想象的要容易得多。$mojo生成应用程序MyApp$cd我的应用程序$mv公共库/MyApp/$mv模板库/MyApp/诀窍是移动C和C目录,以便可以使用模块。另外,从C编写命令命名空间通常不是安装了应用程序,以便可以排除它们。#应用程序包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->主->子(“模板”);#排除作者命令$self->commands->namespaces(['Mojolicious::Command']);我的$r=$self->路线;$r->get('/')->to('example#welcome');}1;最后,只需对应用程序脚本进行一个小的更改。shebang线成为推荐线C<#!perl>,工具链可以在安装过程中将其重写为正确的shebang。#!珍珠严格使用;使用警告;使用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帐户(可以在L申请)甚至上传它。$mojo cpanify-u USER-p传递MyApp-0.01.tar.gz=头2代理当每L应用程序具有内置的用户代理L为你要执行对后端web服务的请求,这并不总是最有效的解决方案。专用代理助手Lget_p“>和L(左)startp“>可以立即将响应内容流式传输到客户端当从后端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网站');my$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');});};应用程序->启动;所有代理助手都返回L对象,该对象应用于处理与后端web的连接错误优雅的服务。如果您需要将所有标头从客户端转发到后端web服务,请确保使用L删除所有逐跳标头。#克隆和修改请求标头my$headers=$c->req->headers->clone->dehop;$headers->accept('application/json');my$tx=$c->ua->build_tx(PUT=>'https://mojolicious.org'=>$headers->to_hash);=head2你好世界如果每个字节都重要,那么这是最小的C可以用L编写的应用程序.使用Mojolicious::Lite;any{text=>“你好,世界!”};应用程序->启动;它之所以有效,是因为所有没有模式的路由都默认为C</>,即使没有实际的代码也会自动呈现由路由器执行。渲染器只拾取C值并生成响应。=head2 Hello World单句C类上面的例子在L中甚至可以短一点单衬里。$perl-Mojo-E'a({text=>“Hello World!”})->start'守护进程你可以使用L中的所有命令.$perl-Mojo-E'a({text=>“Hello World!”})->start'get-v/=头部1更多你可以继续学习L现在或者看看L,其中包含许多不同的文档和示例作者。=头部1支架如果您有任何文档可能尚未回答的问题,请毫不犹豫地在L(左),在L上,或L(左).=切割