mojo lite学习笔记之Url路由
在对mojo有初步认识之后(mojo lite学习笔记之自身用法),接下来介绍它的一个非常赞的功能块:Url路由。-----------------------------
Routes 只是对请求过来的路径指向不同的函数,可以在路径中包含不同的占位符,传进来的第一个参数是 $c($self) 是 Mojolicious::Controller 对象本身, 它也包含着 HTTP request 和 HTTP response 的对象。
根据request进行路由,可以根据:url,param,format,method等进行路由。
--------------
1、Url
这是最基本的路由,即访问什么url会有什么结果。
# /
get '/' => sub {
my $self = shift;
$self->render;
} => 'index';
# /hello
get '/hello';
app->start;
__DATA__
@@ index.html.ep
<%= link_to Hello => 'hello' %>.
<%= link_to Reload => 'index' %>.
@@ hello.html.ep
Hello FreeOA!
--------------
2、占位符-param(参数)
路径选择的占位符可以让你取得一些请求中的路径。结果会可以通过 "stash" in Mojolicious::Controller 和 "param" in Mojolicious::Controller 来访问。即主要有两种方式:
1)、GET/POST 传进来的参数
全部的 GET 和 POST 的参数只需要通过 "param" in Mojolicious::Controller 来访问。
2)、Stash 和模板 (templates)
这个 "stash" in Mojolicious::Controller 是用来传一些数据给模板技术使用, 在这我们使用的模板是存储在 DATA 这个部分中的 @@ 标记的位置内容。
# /foo/test123
get '/foo/:bar' => sub {
my $self = shift;
my $bar = $self->stash('bar');
$self->render(text => "Our :bar placeholder matched $bar");
};
# /testsomething/foo
# /123something/foo
get '/(:bar)something/foo' => sub {
my $self = shift;
my $bar = $self->param('bar');
$self->render(text => "Our :bar placeholder matched $bar");
};
外部参数(传入到脚本中)
通用的用法:url/script.pl?parm1=values1
在mojo中需要像下面这样传参(/:arg)
get '/foo/:bar'
get '/:foo' => sub {
my $self = shift;
my $foo = $self->param('foo');
$self->render(text => "Hello from $foo.");
};
内部传参(传入到模板中)
stash方法与render('模板名',参数列表).
get '/bar' => sub {
my $self = shift;
$self->stash(one => 23);
$self->render('baz', two => 24);
};
app->start;
__DATA__
@@ baz.html.ep
The magic numbers are <%= $one %> and <%= $two %>.
综合使用示例
my $en={'a'=>1,'b'=>2,'c'=>3};
get '/bar' => sub {
my $self = shift;
$self->stash(env =>$en);
$self->render('baz', two => 28);
};
app->start;
__DATA__
@@ baz.html.ep
%# use Data::Dumper;
%== dumper $env;
The magic numbers are <%= $env->{b} %> and <%= $two %>.
--------------
3、松懈占位符
松懈占位可以让你匹配直接到最近的 /
# /test/hello
# /test123/hello
# /test.123/hello
get '/#you/hello' => 'groovy';
app->start;
__DATA__
@@ groovy.html.ep
Your name is <%= $you %>.
--------------
4、通配位符
配位符可以匹配到任何东西,包括 / 和 ..
# /hello/test
# /hello/test123
# /hello/test.123/test/123
get '/hello/*you' => 'groovy';
app->start;
__DATA__
@@ groovy.html.ep
Your name is <%= $you %>.
--------------
5、可选的占位符
即指定一个默认值。
# /hello
# /hello/Sara
get '/hello/:name' => {name => 'Sebastian'} => sub {
my $self = shift;
$self->render('groovy', format => 'txt');
};
app->start;
__DATA__
@@ groovy.txt.ep
My name is <%= $name %>.
--------------
6、限制性占位符
有个最简单的方法,让你的占位符有严格的范围,您只需写出可能值的列表。
# /test
# /123
any '/:foo' => [foo => [qw(test 123)]] => sub {
my $self = shift;
my $foo = $self->param('foo');
$self->render(text => "Our :foo placeholder matched $foo");
};
app->start;
所有的占位符被编译到成正则表达式,所以在这也可以很容易地定制你的这个。
# /1
# /123
any '/:bar' => [bar => qr/\d+/] => sub{
my $self = shift;
my $bar = $self->param('bar');
$self->render(text => "Our :bar placeholder matched $bar");
};
app->start;
只要确保不使用^和$还有捕获组 (...), 因为这些占位符会和内置的组成一个更大的正则表达式.
--------------
HTTP methods
路径选择的方法可以指定 HTTP 的方法,"req" in Mojolicious::Controller 和 "res" in Mojolicious::Controller 提供了全功能的 HTTP 的支持。
# GET /hello
get '/hello' => sub {
my $self = shift;
$self->render(text => 'Hello World!');
};
# PUT /hello
put '/hello' => sub {
my $self = shift;
my $size = length $self->req->body;
$self->render(text => "You uploaded $size bytes to /hello.");
};
# GET|POST|PATCH /bye
any [qw(GET POST PATCH)] => '/bye' => sub {
my $self = shift;
$self->render(text => 'Bye World!');
};
# * /whatever
any '/whatever' => sub {
my $self = shift;
my $method = $self->req->method;
$self->render(text => "You called /whatever with $method.");
};
app->start;
可用curl工具实验:
curl -X POST http://ip:port/whatever
curl -X PUT -d "name=freeoa" http://ip:port/hello
添加一个http头
get '/agent' => sub {
my $self = shift;
$self->res->headers->header('X-Extra' => 'FreeOA Web Server');
$self->render(text => $self->req->headers->user_agent);
};
--------------
Formats(文件格式)
这其实是指的后缀,这个会自动根据后缀来选择。
# /detection.html
# /detection.txt
get '/detection' => sub {
my $self = shift;
$self->render('detected');
};
app->start;
__DATA__
@@ detected.html.ep
<!DOCTYPE html>
<html>
<head><title>Detected</title></head>
<body>HTML was detected.</body>
</html>
@@ detected.txt.ep
TXT was detected.
限制性的的占位符也可以使用。
# /hello.json
# /hello.txt
get '/hello' => [format => [qw(json txt)]] => sub {
my $self = shift;
return $self->render(json=>{hello => 'world'}) if $self->stash('format') eq 'json';
$self->render(text=>'hello world');
};
app->start;
你也可以禁用格式检查
# /hello
get '/hello' => [format => 0] => {text => 'No format detection.'};
# Disable detection and allow the following routes selective re-enabling
under [format => 0];
# /foo
get '/foo' => {text => 'No format detection again.'};
# /bar.txt
get '/bar' => [format => 'txt'] => {text => ' Just one format.'};
app->start;
内容协商
不同的表示方法和需要真正 RESTful 的内容来协商,你可以看看 "respond_to" in Mojolicious::Controller.
# /hello (Accept: application/json)
# /hello (Accept: application/xml)
# /hello.json
# /hello.xml
# /hello?format=json
# /hello?format=xml
get '/hello' => sub {
my $self = shift;
$self->respond_to(
json => {json => {hello => 'world'}},
xml => {text => '<hello>world</hello>'},
any => {data => '', status => 204}
);
};
app->start;
有关 MIME type 的相关后缀的对应关系看 "types" in Mojolicious.
app->types->type(rdf => 'application/rdf+xml');
--------------
据客户端浏览器不同而不同
条件可以是象 agent 和 host 之类的信息, 是从 Mojolicious::Plugin::HeaderCondition 中来的东西.可以提供强大的路由限制.
get '/'=>'index';
# /br (Firefox)
get '/br' => (agent => qr/Firefox/) => sub {
my $c = shift;
$c->render(text => 'Congratulations, you are using a cool browser.');
};
get '/host' => (host => '172.18.0.8') => sub {
my $c = shift;
$c->render(text => 'Hello Local User.');
};
#添加一个自定义的头,可以用firebug工具查看
get '/agent' => sub {
my $self = shift;
$self->res->headers->header('X-Extra' => 'FreeOA Web Server');
$self->render(text => $self->req->headers->user_agent);
};
#在客户端访问时指定一个响应头,可以用curl -H ""工具来测试
get '/hdvalid' => sub {
my $self = shift;
return 1 if $self->req->headers->header('X-Extra');
$self->render(text => "You are missed some header.");
return undef;
}=>'index';
app->start;
__DATA__
@@ index.html.ep
curl -H 'X-Extra:Freeoa' http://172.18.0.8:8000/hdvalid
--------------
Under
认证并共享代码在多个路径之间很容易实现,只需要桥接生成的路由并使用 under 的声明。多个嵌套的路由来共享代码,在碰到下一个under之前,之间的方法会自动套用这些代码。
use Mojolicious::Lite;
# Authenticate based on name parameter
under sub {
my $self = shift;
# Authenticated
my $name = $self->param('name') || '';
return 1 if $name eq 'Freeoa';
# Not authenticated
$self->render('denied');
return undef;
};
# / (with authentication)
get '/' => 'index';
app->start;
__DATA__;
@@ denied.html.ep
You are not Bender, permission denied.
@@ index.html.ep
Hi Freeoa
要实现前缀的多个路径选择,也是一个使用的 under 的好理由。
use Mojolicious::Lite;
# /foo
under '/foo';
# /foo/bar
get '/bar' => {text => 'foo bar'};
# /foo/baz
get '/baz' => {text => 'foo baz'};
# /
under '/' => {message => 'whatever'};
# /bar
get '/bar' => {inline => '<%= $message %> works'};
app->start;
你也可以使用 group 来组织相关的 routes ,这可以对多个路径进行 under 的声明。所有的相关的url只与这个group块有关系,与其它的没有关系,除非定义为全局级别的。
use Mojolicious::Lite;
# Global logic shared by all routes
under '/'=>sub {
my $self = shift;
return 1 if $self->req->headers->header('X-Bender');
$self->render(text => "You're not Bender.");
return undef;
};
# Admin section
group {
# Local logic shared only by routes in this group
under '/admin' => sub {
my $self = shift;
return 1 if $self->req->headers->header('X-Awesome');
$self->render(text => "You're not awesome enough.");
return undef;
};
# GET /admin/dashboard
get '/dashboard' => {text => 'Nothing to see here yet.'};
};
# GET /welcome
get '/welcome' => {text => 'Hi Bender.'};
app->start;
请求示例:curl -H "X-Bender:Freeoa" http://172.18.0.8:8000/welcome