=编码utf8=头1名称Mojolicious::Guides::路由-路由请求=标题1概述本文档包含对L的简单而有趣的介绍路由器及其基本概念。=头1概念每升基本装备开发人员应该知道。=头部2调度员每个web框架的基础都是一个小黑匣子,它将传入的请求与生成适当的回应。GET/user/show/1->$c->render(text=>'Daniel');这个黑盒子通常被称为调度员。有许多实现使用不同的策略来建立这些连接,但几乎都是基于将请求URL的路径部分映射到某种类型的响应生成器。/user/show/2->$c->render(text=>'Isabell');/user/show/3->$c->render(text=>“Sara”);/user/show/4->$c->render(text=>'Stefan');/user/show/5->$c->render(text=>'Fynn');虽然很可能使所有这些连接都是静态的,但效率也相当低。这就是为什么经常表达式通常用于使调度过程更加动态。qr/用户/显示/(\d+)!->$c->render(文本=>$users{$1});现代调度器拥有HTTP所能提供的几乎所有功能,并且可以使用比以下更多的变量只有请求路径,例如请求方法和标题,如C,C和C.GET/user/show/23 HTTP/1.1主持人:mojolicious.org用户代理:Mojolicus(Perl)接受:text/html、application/xhtml+xml、application/xml;q=0.9,*/*;q=0.8=头2路线虽然正则表达式非常强大,但它们也往往看起来不太好,而且通常使用起来过于繁琐普通路径匹配。qr/用户/管理员/(\d+)!->$c->render(文本=>$users{$1});这就是路线发挥作用的地方,它们从地面开始设计,用占位符表示路径。/user/admin/:id->$c->render(文本=>$users{$id});静态路径和上面的路由之间的唯一区别是C<:id>占位符。一个或多个占位符可以在路线上的任何地方。/用户/:角色/:idL的基本概念路由器将提取的占位符值转换为散列。/user/admin/23->/user/:role/:id->{role=>“admin”,id=>23}这个散列基本上是每个L的中心应用程序,稍后您将了解更多信息。在内部,路由被编译为正则表达式,因此您可以使用一点体验。/用户/管理员/:id->qr/(?-xism:^\/user\/admin\/([^\/.]+))/路径中的尾部斜杠始终是可选的。/user/admin/23/->/user/:role/:id->{role=>'admin',id=>23}=头部2可逆性与正则表达式相比,路由还有一个巨大的优势,那就是它们很容易可逆,可以提取占位符可以随时变回路径。/sebastian->/:name->{name=>“sebastian”}{name=>“sebastian”}->/:name->/sebastian每个占位符都有一个名称,即使它只是一个空字符串。=head2标准占位符标准占位符是最简单的占位符形式,它们使用冒号前缀并匹配除C</>和C<.>,类似于正则表达式C<([^/.]+)>。/hello->/:name/hello->undef/塞巴斯蒂安/23/hello->/:name/hello->undef/sebastian.23/hello->/:name/hello->undef/sebastian/hello->/:name/hello->{name=>“sebastian”}/sebastian23/hello->/:name/hello->{name=>“sebastian 23”}/塞巴斯蒂安23/hello->/:name/hello->{name=>'sebastian 23'}所有占位符都可以用C括起来>和C>将它们与周围的文本分开。/hello->/<:name>hello->unde/塞巴斯蒂安/23你好->/<:name>你好->unde/sebastian.23hello->/<:name>hello->undef/sebastianhello->/<:name>hello->{name=>“sebastian”}/sebastian23hello->/<:name>hello->{name=>“sebastian 23”}/塞巴斯蒂安23hello->/<:name>hello->{name=>'sebastian 23'}冒号前缀对于由C包围的标准占位符是可选的>和C>./我令人兴奋->/->{one=>“i”,two=>“mojolicious”}=head2松弛占位符松弛占位符与标准占位符类似,但使用散列前缀并匹配除C之外的所有字符,类似于正则表达式C<([^/]+)>。/hello->/#name/hello->unde/塞巴斯蒂安/23/hello->/#name/hello->undef/sebastian.23/hello->/#name/hello->{name=>'sebastiang.23'}/sebastian/hello->/#name/hello->{name=>“sebastian”}/sebastian23/hello->/#name/hello->{name=>“sebastian 23”}/塞巴斯蒂安23/hello->/#name/hello->{name=>'sebastian 23'}它们对于手动匹配文件名和扩展名特别有用,而不是使用L./music/song.mp3->/music/#filename->{filename=>'song.mp3'}=head2通配符占位符通配符占位符与上面的两种占位符类似,但使用星号前缀并匹配绝对是一切,包括C</>和C<.>,类似于正则表达式C<(.+)>。/hello->/*name/hello->unde/塞巴斯蒂安/23/hello->/*name/hello->{name=>'sebastian/23'}/sebastian.23/hello->/*name/hello->{name=>'sebastiang.23'}/sebastian/hello->/*name/hello->{name=>“sebastian”}/sebastian23/hello->/*name/hello->{name=>“sebastian 23”}/塞巴斯蒂安23/hello->/*name/hello->{name=>'sebastian 23'}它们对于手动匹配整个文件路径非常有用。/music/rock/song.mp3->/music/*文件路径->{文件路径=>'rock/song.mp3'}=头部1基本每个L最常用的功能开发人员应该知道。=头2最小路线属性L包含可用于生成路由结构的路由器。#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#路由器我的$r=$self->路线;#路线$r->get('/welcome')->to(controller=>'foo',action=>'welcome'');}1;上面的最小路由将加载并实例化类C并将其命名为C方法。路由通常在C中配置方法,但可以从无处不在(甚至在运行时)。#控制器包MyApp::控制器::Foo;使用Mojo::Base“Mojolicious::Controller”,-签名;#行动子欢迎($self){#渲染响应$self->render(text=>“你好”);}1;所有路由都以定义它们的相同顺序进行匹配,一旦找到合适的路由,匹配就会停止找到。因此,您可以通过首先声明最常访问的路由来提高路由性能。一条路线缓存还将自动用于更优雅地处理突发流量峰值。=head2路由目的地使用L等方法开始新路线后,你也可以给它一个目的地以散列的形式使用链式方法L.#/welcome->{controller=>'foo',action=>'welcome'}$r->get('/welcome')->to(controller=>'foo',action=>'welcome'');现在,如果路由匹配传入的请求,它将使用此散列的内容来尝试查找合适的代码生成响应。=head2 HTTP方法对于最常见的HTTP请求方法(如L),已经有了快捷方式、和用于更多控制L接受具有任意请求方法的可选数组引用第一个参数。#PUT/hello->取消定义#GET/hello->{controller=>'foo',action=>'hello'}$r->get('/hello')->to(controller=>'foo',action=>'hello');#PUT/hello->{controller=>“foo”,action=>“hello”}$r->put('/hello')->to(controller=>'foo',action=>'hello');#POST/hello->{controller=>'foo',action=>'hello'}$r->post('/hello')->to(controller=>'foo',action=>'hello');#获取| POST/bye->{controller=>“foo”,action=>“bye”}$r->any(['GET','POST']=>'/bey')->to(controller=>'foo',action=>'bye');#*/whatech->{controller=>'foo',action=>'whatech'}$r->any('/anthe')->to(controller=>'foo',action=>'whatever');有一个小例外,C请求被视为等于C,但内容不会与一起发送即使有回应。#GET/test->{controller=>'bar',action=>'test'}#头部/测试->{控制器=>“bar”,动作=>“test”}$r->get('/test')->to(controller=>'bar',action=>'test');您还可以使用C<_method>查询参数覆盖请求方法。这在提交时非常有用带有仅支持C的浏览器的表单和C.#PUT/stuff->{controller=>“baz”,action=>“stuff”}#帖子/东西_方法=PUT->{controller=>“baz”,操作=>“stuff”}$r->put(“/stuff”)->to(controller=>baz,action=>stuff);=头部2 IRIIRI的处理是透明的,这意味着路径可以保证从字节到字符的非转义和解码。#GET(获取)/(Unicode雪人)->{controller=>'foo',action=>'snowman'}$r->获取('/☃')->到(控制器=>“foo”,动作=>“雪人”);=头部2 Stash匹配路由的生成散列实际上是整个L的中心请求周期。我们称之为stash,它会一直持续到生成响应。#/bye->{controller=>'foo',action=>'bye',mymessage=>'bye'}$r->get('/bye')->to(controller=>'foo',action=>'bye',mymessage=>'bye');有一些具有特殊含义的stash值,例如C和C,但您通常可以填充使用生成响应所需的任何数据。一旦发送,整个存储内容可以随时更改。再见($self){#从藏匿处获取消息my$msg=$self->stash('mmessage');#更改隐藏邮件$self->stash(mymessage=>“欢迎”);}你可以用L设置应用程序中随处可用的默认存储值。$app->defaults(mymessage=>“你好”);有关保留存储值的完整列表,请参阅L.=头2嵌套路线还可以从路由中构建树结构以删除重复代码。有孩子的路线无法匹配但就其本身而言,只有这些嵌套路由的实际端点可以。#/foo->undef#/foo/bar->{controller=>'foo',action=>'bar'}my$foo=$r->any('/foo')->to(controller=>'foo');$foo->get('/bar')->to(action=>'bar');存储只是从一个路由继承到另一个路由,新值覆盖旧值。#/cats->{controller=>“cats”,action=>“index”}#/cats/nyan->{controller=>'cats',action=>'nyan'}#/cats/lol->{controller=>“cats”,action=>“default”}my$cats=$r->any('/cats')->to(controller=>'cats',action=>'default');$cats->get('/')->to(action=>'index');$cats->get('/nyan')->to(action=>'nyan');$cats->get('/lol');通过几个常见的前缀,您还可以大大提高具有许多路由的应用程序的路由性能,因为只有在前缀首先匹配的情况下才会尝试孩子。=head2特殊存储值当调度员看到C时和C它将始终尝试将其转换为类和方法。C值从C转换至C使用L(左)并附加到一个或多个名称空间,默认为基于应用程序类(C)以及裸应用程序类(C),并且这些命名空间是按顺序搜索。动作值根本没有更改,因此这两个值都区分大小写。#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#/bye->MyApp::控制器::Foo->bye$self->路由->get('/bey')->to(controller=>'foo',action=>'bye');}1;#控制器包MyApp::控制器::Foo;使用Mojo::Base“Mojolicious::Controller”,-签名;#行动再见($self){#渲染响应$self->render(text=>“再见”);}1;控制器类非常适合组织大型项目中的代码。有更多的调度策略,但因为控制器是最常用的控制器,它们还有一个特殊的快捷方式,即C.#/bye->{controller=>'foo',action=>'bye',mymessage=>'bye'}$r->get('/bye')->to('foo#bye',mymessage=>'bye');在camelization过程中,C<->字符被替换为C<::>,这允许多级C层次结构。#/->MyApp::控制器::Foo::Bar->hi$r->get('/')->to('foo-bar#hi');您也可以只指定C以CamelCase形式代替snake_case。#/->MyApp::控制器::Foo::Bar->hi$r->get('/')->to('Foo::Bar#hi');出于安全原因,调度员将始终检查C实际上是的子类L(左)或L然后发送给它。=head2命名空间你可以使用Cstash值以更改整个路由及其所有子路由的名称空间。#/bye->MyApp::MyController::Foo::Bar->bye$r->get('/bye')->to(namespace=>“MyApp::MyController”,controller=>“Foo::Bar”,action=>“bye”);C类始终从C转换至C带L,然后附加到此C.#/bye->MyApp::MyController::Foo::Bar->bye$r->get('/bey')->to('foo-bar#bye',namespace=>'MyApp::MyController');#/hey->MyApp::MyController::Foo::Bar->hey$r->get('/hey')->to('Foo::Bar#hey',namespace=>'MyApp::MyController');您还可以使用router属性更改应用程序中所有路由的默认名称空间L(左),通常默认为基于应用程序类的命名空间(C))以及裸应用程序类(C).$r->名称空间([“MyApp::MyController”]);=head2回拨路线C类stash值不会被嵌套路由继承,可以用来绕过控制器并执行改为回调。$r->get('/bey')->to(cb=>sub($c){$c->render(text=>“再见”);});但就像L一样您还可以直接传递回调,这通常看起来要好得多。$r->get('/bye'=>sub($c){$c->render(text=>“再见”);});=head2命名路线命名路由将允许在整个框架中的许多方法和帮助程序中进行反向引用,其中大多数内部依赖L为了这个。#/foo/marcus->{controller=>'foo',action=>'bar',user=>'marcus'}$r->get('/foo/:user')->to('foo#bar')->name('baz');#为路由“baz”生成URL“/foo/marcus”(在前面的请求上下文中)我的$url=$c->url_for(“baz”);#为路由“baz”生成URL“/foo/jan”我的$url=$c->url_for('baz',用户=>'jan');#生成URL“http://127.0.0.1:3000/foo/jan用于路线“baz”我的$url=$c->url_for('baz',user=>'jan')->to_abs;您可以使用L指定名称,或者让路由器自动生成一个将等于没有非单词字符的路由本身,但自定义名称具有更高的优先级。#/foo/bar(“foobar”)$r->get('/foo/bar')->to('test#stuff');#生成URL“/foo/bar”我的$url=$c->url_for('foobar');要引用当前路线,可以使用保留名称C或者根本没有名字。#为当前路由生成URL我的$url=$c->url_for('当前');我的$url=$c->url_fo;要检查或获取当前路线的名称,可以使用助手L(左).#当前路线的名称我的$name=$c->current_route;#在多条路线共享的代码中检查路线名称如果$c->current_route(“登录”)为$c->stash(button=>“绿色”);=head2可选占位符提取的占位符值将简单地重新定义旧的存储值(如果它们已经存在)。#/bye->{controller=>'foo',action=>'bar',mymessage=>'bye'}#/hey->{controller=>'foo',action=>'bar',mymessage=>'hey'}$r->get('/:mymessage')->to('foo#bar',mymessage=>'hi');还有一个有趣的效果,如果已经存在相同的隐藏值,则占位符会自动变为可选的name present,其工作原理类似于正则表达式C<([^/.]+)?>。#/->{controller=>'foo',action=>'bar',mymessage=>'hi'}$r->get('/:mymessage')->to('foo#bar',mymessage=>'hi');#/test/123->{controller=>'foo',action=>'bar',mymessage=>'hi'}#/test/bye/123->{controller=>'foo',action=>'bar',mymessage=>'bye'}$r->get('/test/:mymessage/123')->to('foo#bar',mymessage=>'hi');如果两个可选占位符只由斜线分隔,那么斜线也可以成为可选的。=head2限制占位符使占位符更具限制性的一个非常简单的方法是替代方法,您只需列出可能的值然后类似于正则表达式C<(bender|leela)>。#/fry->undef#/bender->{controller=>'foo',action=>'bar',name=>'bender'}#/leela->{controller=>'foo',action=>'bar',name=>'leela'}$r->get('/:name'=>[name=>['bender','leela']])->to('foo#bar');您还可以直接调整占位符后面的正则表达式,只需确保不要使用C<^>和C<$>或捕获组C<(…)>,因为占位符在内部成为较大正则表达式的一部分,因此无法捕获但C组情况良好。#/23->{controller=>'foo',action=>'bar',number=>23}#/test->undef$r->get('/:number'=>[number=>qr/\d+/])->to('foo#bar');#/23->未定义#/test->{controller=>'foo',action=>'bar',name=>'test'}$r->get('/:name'=>[name=>qr/[a-zA-Z]+/])->to('foo#bar');通过这种方式,您可以获得易于阅读的路由和正则表达式的原始功能。=head2占位符类型如果您有多条使用限制性占位符的路由,也可以使用L(左).#有备选方案的类型$r->add_type(futurama_name=>['bender','leela']);#/fry->undef#/bender->{controller=>'foo',action=>'bar',name=>'bender'}#/liela->{controller=>“foo”,action=>“bar”,name=>“leela”}$r->获取('/')->到('foo#bar');占位符类型的工作原理与限制性占位符类似,它们只是可与C类占位符:typeE>符号。#调整正则表达式的类型$r->add_type(上部=>qr/[A-Z]+/);#/user/ROOT->{controller=>'users',action=>'show',name=>'ROOT'}#/user/root->undef#/user/23->取消定义$r->get('/user/')->到('用户#show');一些类型,如C非常常用,因此默认情况下可以使用。#/article/12->{controller=>“article”,action=>“show”,id=>12}#/article/test->undef$r->get('/article/')->到('文章#节目');有关可用占位符类型的完整列表,另请参阅L.=头部2反思命令L可以从命令行中使用,将所有可用的路由列在一起包含名称和基本正则表达式。$ ./myapp.pl路由-v/foo/:名称。。。。POST fooname ^/foo/([^/.]+)/?(?:\.([^/]+))?$/酒吧。。U.*巴^/巴+/呸。。。获取baz^/baz/?(?:\.([^/]+))?$/雅达….*雅达^/雅达/?(?:\.([^/]+))?$=头部2下方若要与多个嵌套路由共享代码,可以使用L,因为与正常情况不同嵌套的路由,用它生成的路由有自己的中间目的地并导致额外的调度当它们匹配时循环。#/foo->undef#/foo/bar->{controller=>'foo',action=>'baz'}#{controller=>'foo',action=>'bar'}我的$foo=$r->under('/foo')->to('foo#baz');$foo->get('/bar')->to('#bar');此目的地的实际操作代码需要返回一个真值,否则调度链将断开,这可能成为一个非常强大的身份验证工具。#/blackjack->{cb=>sub{…}}#{controller=>“隐藏”,action=>“21点”}我的$auth=$r->under('/'=>sub($c){#已验证身份如果$c->req->headers->header('X-Bender'),则返回1;#未验证$c->render(text=>“You're not Bender”,status=>401);返回undef;});$auth->get('/blackjack')->to('hideout#blackjack]);可以通过调用L继续断开的调度链,这允许例如,在到达下一个调度周期之前完成非阻塞操作。我的$maybe=$r->在('/maybe'=>sub($c)下{#等待3秒钟,然后给访客50%的机会继续Mojo::IOLoop->计时器(3=>sub{#失败者return$c->render(text=>'No luck.'),除非int rand 2;#优胜者$c->继续;});返回undef;});$maybe->get('/')->to('maybe#winner');每个目的地都只是路线匹配时存储的快照,只有C共享价值他们所有人。要获得更多动力,您可以使用L(左).#第四个调度周期的操作我的$action=$c->match->stack->[3]{action};=head2格式可以检测到路径末尾的文件扩展名,如C<.html>和C<.txt>,并将其存储在存储值C中.使用限制性占位符声明可能的值。#/foo.txt->未定义#/foo.rss->{controller=>'foo',action=>'bar',format=>'rss'}#/foo.xml->{controller=>'foo',action=>'bar',format=>'xml'}$r->get('/foo'=>[format=>['rss','xml']])->to('foo#bar');例如,允许不同格式的多个模板共享相同的操作代码。就像占位符,您可以使用默认值使格式可选。#/foo->{controller=>'foo',action=>'bar'}#/foo.html->{controller=>“foo”,action=>“bar”,format=>“html”}#/foo.txt->{controller=>“foo”,action=>“bar”,format=>“txt”}$r->get('/foo'=>[format=>['html','txt']])->to('foo#bar',format=>undef);格式可以由嵌套路由继承。#/foo->{controller=>'foo',action=>'one',format=>undef}#/foo.html->{controller=>“foo”,action=>“one”,format=>“html”}#/foo.json->{controller=>'foo',action=>'one',format=>'json'}#/bar->{controller=>'bar',action=>'two',format=>undef}#/bar.html->{controller=>“bar”,action=>“two”,format=>“html”}#/bar.json->{controller=>'bar',action=>'two',format=>'json'}my$with_format=$r->any('/'=>[format=>['html','json']])->to(format=>undef);$with_format->get('/foo')->to('foo#one');$with_format->get('/bar')->to('bar#two');A和C值也可以传递给L.#/foo/23.txt->{controller=>“foo”,action=>“bar”,id=>23,format=>“txt”}$r->get('/foo/:id')->to('foo#bar')->name('baz');#为路由“baz”生成URL“/foo/24.txt”我的$url=$c->url_for('baz',id=>24,format=>'txt');=头2 WebSockets使用方法L您可以限制对WebSocket握手的访问,这是正常C带有一些附加信息的请求。#/echo(WebSocket握手)$r->websocket('/echo')->to('foo#echo');#控制器包MyApp::控制器::Foo;使用Mojo::Base“Mojolicious::Controller”,-签名;#行动子回波($self){$self->on(message=>sub($self,$msg){$self->send(“回声:$msg”);});}1;当您以C<101>响应状态响应WebSocket握手请求时,就会建立连接,如果您订阅了带有L的事件,则会自动发生或发送消息L(左)马上。GET/echo HTTP/1.1主持人:mojolicious.org用户代理:Mojolicious(Perl)连接:升级升级:websocketSec-WebSocket密钥:IDM3ODE4NDk2MjA1OTcxOQ==Sec-WebSocket-Version:13HTTP/1.1 101交换协议服务器:Mojolicious(Perl)日期:2015年2月3日星期二17:08:24 GMT连接:升级升级:websocketSec-WEB插座验收:SWsp5N2iNxPbHlcOTIw8ERvyVPY==head2全面路线由于路由按定义顺序匹配,因此可以捕获上次不匹配的所有请求使用可选的通配符占位符进行路由。# * /*$r->any(“/*whatever”=>{whatever=>''}=>sub($c){my$whatever=$c->param(“whatever”);$c->render(text=>“/$whatever did not matched.”,status=>404);});=头部2条件C等条件,C和C从L开始可以应用于任何方法L的路线,并允许更强大的路由构造。#/(来源:http://perl.org)$r->get('/')->需要(headers=>{Origin=>qr/perl\.org/})->to('foo#bar');#/(Firefox)$r->get('/')->需要(agent=>qr/Firefox/)->to('browser-test#Firefox');#/(Internet Explorer)$r->get('/')->需要(agent=>qr/Internet Explorer/)->to('browser-test#ie');#http://docs.mojolicious.org/mojolicious网站$r->get('/')->需要(host=>'docs.mojolicious.org')->to('perldoc#index');请注意,对于路由缓存来说,情况太复杂了,这通常会加快重复请求的速度,并且因此会降低性能。=头部2个挂钩钩子在路由系统之外运行,允许您通过与所有请求共享代码来扩展框架本身不加选择地通过L,这使得它们成为一个非常强大的工具,特别是对于插件。#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#检查所有“/test”前缀请求$self->hook(before_dispatch=>sub($c){如果$c->req->url->path->contains('/test');});#如果上面的钩子呈现响应,则无法达到这些目标我的$r=$self->路线;$r->get('/welcome')->to('foo#welcome'');$r->post('/bey')->to('foo#bye');}1;对响应进行后处理以添加或删除标头是一种非常常见的用法。#确保缓存静态文件$app->hook(after_static=>sub($c)){$c->res->headers->cache_control('max-age=3600,必须重新验证');});#删除默认标题$app->hook(after_dispatch=>sub($c)){$c->res->headers->remove(“服务器”);});预处理请求也是如此。#根据请求标头选择模板变量$app->hook(before_dispatch=>sub($c)){除非我的$agent=$c->req->headers->user_agent,否则返回;如果$agent=~/Internet Explorer/;,$c->stash(variant=>'ie');});或更高级的扩展来为应用程序添加监视功能。#将异常转发到web服务$app->hook(after_dispatch=>sub($c)){返回,除非我的$e=$c->stash('exception');$c->ua->帖子('https://example.com/bug'=>form=>{exception=>$e});});您甚至可以扩展大部分核心功能。#使控制器对象可用于操作$_$app->hook(around_action=>sub($next,$c,$action,$last){本地$_=$c;return$next->();});#将路由名称作为参数传递给操作$app->hook(around_action=>sub($next,$c,$action,$last){返回$c->$action($c->current_route);});有关可用挂钩的完整列表,请参阅L.=头部1高级不太常用且功能更强大的功能。=head2快捷方式为了使路线生成更具表现力,您还可以使用添加自己的快捷方式L(左).#简单的“资源”快捷方式$r->add_shortcut(资源=>sub($r,$name){#资源的前缀我的$resource=$r->any(“/$name”)->to(“$name#”);#呈现资源列表$resource->get('/')->to('#index')->name($name);#呈现表单以创建新资源(提交到“存储”)$resource->get('/create')->to('#create')->name(“create_$name”);#存储新创建的资源(由“create”提交)$resource->发布->到(“#store”)->名称(“store_$name”);#呈现特定资源$resource->get('/:id')->to('#show')->name(“show_$name”);#呈现表单以编辑资源(提交给“更新”)$resource->get('/:id/edit')->to('#edit')->name(“edit_$name”);#存储更新的资源(由“编辑”提交)$resource->put('/:id')->to('#update')->name(“update_$name”);#删除资源$resource->delete('/:id')->to('#remove')->name(“remove_$name”);返回$resource;});#GET/users->{controller=>'users',action=>'index'}#GET/users/create->{controller=>'users',action=>'create'}#POST/users->{controller=>'users',action=>'store'}#GET/users/23->{controller=>'users',action=>'show',id=>23}#GET/users/23/edit->{controller=>'users',action=>'edit',id=>23}#PUT/users/23->{controller=>'users',action=>'update',id=>23}#DELETE/users/23->{controller=>'users',action=>'remove',id=>23}$r->资源(“用户”);=head2重新安排路线从应用程序启动到第一个请求到达,所有路由仍然可以移动,甚至可以删除像L这样的方法和L.#GET/example/show->{controller=>'example',action=>'show'}我的$show=$r->get('/show')->to('example#show');$r->any('/example')->add_child($show);#什么都没有$r->get('/secrets/show')->to('secrets#show';$r->find('show_secrets')->remove($r->查找('show_secrets')->删除);特别是对于重新排列由插件创建的路由,这可能非常有用,可以使用按其名称查找路由L(左).#GET/example/test->{controller=>'example',action=>'test'}$r->get('/othing/else')->to('something#else')->name('test');我的$test=$r->find(“测试”);$test->pattern->parse(“/example/test”);$test->pattern->defaults({controller=>'example',action=>'test'});即使路线模式和目的地仍然可以用L更改L(左).=head2添加条件您还可以使用方法L添加自己的条件。所有条件都是基本上是每次新请求到达时运行的路由器插件,需要返回路由的真实值以匹配。#随机允许路由匹配的条件$r->add_condition(随机=>sub($route,$c,$captures,$num){#失败者如果int rand$num;则返回undef;#优胜者返回1;});#/可能(25%的可能性)$r->get('/maybe')->需要(random=>4)->to('foo#bar');使用您需要的任何请求信息。#检查查询参数的条件(适用于模拟web服务)$r->add_condition(查询=>sub($route,$c,$captures,$hash){对于我的$key(keys%$hash){我的$param=$c->req->url->query->param($key);返回undef,除非定义了$param&&$param eq$hash->{$key};}返回1;});#/你好?to=世界测试=1$r->get('/hello')->需要(query=>{test=>1,to=>'world'})->to('foo#bar');=head2条件插件您还可以将条件打包为可重用插件。#插件软件包Mojolicious::Plugin::WerewolfCondition;使用Mojo::Base“Mojolicious::Plugin”,-signatures;使用Astro::MoonPhase;子寄存器($self、$app、$conf){#添加“狼人”条件$app->routes->add_condition(狼人=>sub($route,$c,$captures,$days){#把狼人挡在外面!如果abs(14-(阶段(时间))[2])>($days/2),则返回undef;#没关系,没有狼人返回1;});}1;现在只需加载插件,您就可以在所有应用程序中使用该条件了。#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#插件$self->插件('WerewolfCondition');#/藏身处(满月后将其隔离4天)$self->routes->get('/hideout')->requires(狼人=>4)->to(controller=>'foo',action=>'bar');}1;=头部2安装应用将一个应用程序嵌入到另一个中最简单的方法是L,它允许您安装整个域和/或前缀下的自包含应用程序。使用Mojolicus::Lite-签名;#安装在“/prefix”下的整个应用程序插件安装=>{'/prefix'=>'/home/sri/myapp/script/myapp'};#使用子域装载应用程序插件安装=>{“test.example.com”=>“/home/sri/myapp2.pl”};#正常路线获取“/”=>子($c){$c->render(text=>“你好,世界!”);};应用程序->启动;=head2嵌入式应用程序为了获得更多的功能,您还可以通过使用应用程序而不是控制器来嵌入应用程序。例如,这允许,L的使用正常L中的领域特定语言控制器。#控制器程序包MyApp::Controller::Bar;使用Mojolicus::Lite-签名;#/你好获取'/hello'=>sub($c){my$name=$c->param('name');$c->render(text=>“Hello$name”);};1;使用属性L,您可以允许路由部分匹配,并仅使用嵌入式应用程序中的剩余路径,基本路径将在C中传递存储值。#/foo个/*$r->any('/foo')->partial(1)->to('bar#',name=>'Mojo');最小可嵌入应用程序只不过是L的一个子类,包含C方法接受L物体。软件包MyApp::Controller::Bar;使用Mojo::Base“Mojolicious”,-签名;子处理程序($self,$c){$c->res->code(200);my$name=$c->param('name');$c->res->body(“Hello$name.”);}1;主机应用程序通过存储与嵌入式应用程序共享的信息很少。所以你当前无法在通向嵌入式应用程序的路由中使用路由占位符,因为这会导致问题带L.=head2应用程序插件您甚至可以将应用程序打包为独立的可重用插件。#插件软件包Mojolicious::Plugin::MyEmbeddedApp;使用Mojo::Base“Mojolicious::Plugin”,-signatures;子寄存器($self、$app、$conf){#自动添加路由$app->routes->any('/foo')->partial(1)->to(app=>EmbeddedApp::app());}包EmbeddedApp;使用Mojolicious::Lite;获取'/bar'=>'bar';1;__数据__@@bar.html.ep你好,世界!C类stash值不会被嵌套路由继承,可以用于已经实例化的应用程序。现在只需加载插件即可。#应用程序包MyApp;使用Mojo::Base“Mojolicious”,-签名;子启动($self){#插件$self->插件(“MyEmbeddedApp”);}1;=头部1更多你可以继续学习L现在或者看看L,其中包含许多不同的文档和示例作者。=头部1支架如果您有任何文档可能还没有回答的问题,请毫不犹豫地在L(左),在L上,或L(左).=切割