简介
# Controller
package MyApp::Controller::Foo;
use Mojo::Base 'Mojolicious::Controller';
# Action
sub bar {
my $self = shift;
my $name = $self->param('name');
$self->res->headers->cache_control('max-age=1, no-cache');
$self->render(json => {hello => $name});
}
Mojolicious::Controller是Mojolicious应用程序中控制器的基类。如果你没有在Mojolicious中设置“controller_class”,Mojolicious::Controller将被作为默认的控制器类。
属性
Mojolicious::Controller从Mojo::Base继承所有属性,并实现以下属性。
app
my $app = $c->app;
$c = $c->app(Mojolicious->new);
反向引用分配给该控制器的应用程序,通常是Mojolicious对象。
# Use application logger
$c->app->log->debug('Hello Mojo');
# Generate path
my $path = $c->app->home->child('templates', 'foo', 'bar.html.ep');
match
my $m = $c->match;
$c = $c->match(Mojolicious::Routes::Match->new);
当前请求的路由结果,默认为Mojo::Routes::Match对象。
# Introspect
my $name = $c->match->endpoint->name;
my $foo = $c->match->endpoint->pattern->defaults->{foo};
my $action = $c->match->stack->[-1]{action};
tx
my $tx = $c->tx;
$c = $c->tx(Mojo::Transaction::HTTP->new);
正在处理的事务,通常是Mojo::Transaction::HTTP或Mojo::Transaction::WebSocket对象。
注:此引用通常会用被消弱,因此,当你执行非阻塞操作并且底层连接可能会提前关闭时,该对象需要在别处引用。
# Check peer information
my $address = $c->tx->remote_address;
my $port = $c->tx->remote_port;
# Increase size limit for WebSocket messages to 16MiB
$c->tx->max_websocket_size(16777216) if $c->tx->is_websocket;
# Perform non-blocking operation without knowing the connection status
my $tx = $c->tx;
Mojo::IOLoop->timer(2 => sub {
$c->app->log->debug($tx->is_finished ? 'Finished' : 'In progress');
});
方法
Mojolicious::Controller继承Mojo::Base中的所有方法,并实现以下方法。
continue
$c->continue;
使用Mojolicious::Routes中的continue方法从 已经包装的“调度器”链中继续调度。
cookie
my $value = $c->cookie('foo');
$c = $c->cookie(foo => 'bar');
$c = $c->cookie(foo => 'bar', {path => '/'});
获取一个“请求”中的cookie,或设置一个“响应”中的cookie。如果有多个cookie值共享同一个名称,使用这个方法只能获取到最后一个,如果你想获取到所有的值可以使用every_cookie方法。
# Create response cookie with domain and expiration date
$c->cookie(user => 'sri', {domain => 'example.com', expires => time + 60});
# Create secure response cookie
$c->cookie(secret => 'I <3 Mojolicious', {secure => 1, httponly => 1});
every_cookie
my $values = $c->every_cookie('foo');
和cookie方法的功能类似,但返回的是一个包含所有相同名称所有cookie值的数组引用。
$ Get first cookie value
my $first = $c->every_cookie('foo')->[0];
every_param
my $values = $c->every_param('foo');
和param方法的功能类似,但返回的是一个包含所有相同名称所有param值的数组引用。
# Get first value
my $first = $c->every_param('foo')->[0];
every_signed_cookie
my $values = $c->every_signed_cookie('foo');
和signed_cookie方法的功能类似,但返回的是一个包含相同名称所有已签名cookie值的数组引用。
# Get first signed cookie value
my $first = $c->every_signed_cookie('foo')->[0];
finish
$c = $c->finish;
$c = $c->finish(1000);
$c = $c->finish(1003 => 'Cannot accept data!');
$c = $c->finish('Bye!');
关闭WebSocket连接或长时间轮询流,此方法将自动响应具有101响应状态的WebSocket握手请求,以建立WebSocket连接。
flash
my $foo = $c->flash('foo');
$c = $c->flash({foo => 'bar'});
$c = $c->flash(foo => 'bar');
只能在下一次请求中可用的持久存储,会被存储在session中。
# Show message after redirect
$c->flash(message => 'User created successfully!');
$c->redirect_to('show_user', id => 23);
helpers
my $helpers = $c->helpers;
返回包含当前控制器对的代理对象,可以使用他调用由app提供的helpers。这包括Mojolicious::Plugin::DefaultHelpers和Mojolicious::Plugin::TagHelpers中的所有helpers。
# Make sure to use the "title" helper and not the controller method
$c->helpers->title('Welcome!');
# Use a nested helper instead of the "reply" controller method
$c->helpers->reply->not_found;
on
my $cb = $c->on(finish => sub {...});
订阅tx的事件,通常是Mojo::Transaction::HTTP或Mojo::Transaction::WebSocket对象。此方法将自动响应具有101响应状态的WebSocket握手请求,以建立WebSocket连接。
# Do something after the transaction has been finished
$c->on(finish => sub {
my $c = shift;
$c->app->log->debug('All data has been sent');
});
# Receive WebSocket message
$c->on(message => sub {
my ($c, $msg) = @_;
$c->app->log->debug("Message: $msg");
});
# Receive JSON object via WebSocket message
$c->on(json => sub {
my ($c, $hash) = @_;
$c->app->log->debug("Test: $hash->{test}");
});
# Receive WebSocket "Binary" message
$c->on(binary => sub {
my ($c, $bytes) = @_;
my $len = length $bytes;
$c->app->log->debug("Received $len bytes");
});
param
my $value = $c->param('foo');
$c = $c->param(foo => 'ba;r');
$c = $c->param(foo => 'ba;r', 'baz');
$c = $c->param(foo => ['ba;r', 'baz']);
顺序访问路径占位符没有被隐藏的值,文件上传,GET和POST请求中使用application/x-www-form-urlencoded 或 multipart/form-data 格式编码的消息体。如果有多个值共享相同的名称,使用此方法只能得到众值中的最后一个值。如果你想访问所有的值,则需要使用every_param方法。
注:“请求体”每个Parts 都需要加载到内存中被解析,所以需要确保它不会太大。默认情况下限制为16MiB。
# Get first value
my $first = $c->every_param('foo')->[0];
为了更精确和方便的访问,您可以使用以下类似方式直接访问请求信息。
# Only GET parameters
my $foo = $c->req->query_params->param('foo');
# Only POST parameters
my $foo = $c->req->body_params->param('foo');
# Only GET and POST parameters
my $foo = $c->req->param('foo');
# Only file uploads
my $foo = $c->req->upload('foo');
redirect_to
$c = $c->redirect_to('named', foo => 'bar');
$c = $c->redirect_to('named', {foo => 'bar'});
$c = $c->redirect_to('/index.html');
$c = $c->redirect_to('http://example.com/index.html');
准备一个302(如果当前状态吗不是3xx)状态码,使用Location头的重定向响应,参数要求与url_for方法相同。
# Moved Permanently
$c->res->code(301);
$c->redirect_to('some_route');
# Temporary Redirect
$c->res->code(307);
$c->redirect_to('some_route');
render
my $bool = $c->render;
my $bool = $c->render(foo => 'bar', baz => 23);
my $bool = $c->render(template => 'foo/index');
my $bool = $c->render(template => 'index', format => 'html');
my $bool = $c->render(data => $bytes);
my $bool = $c->render(text => 'Hello!');
my $bool = $c->render(json => {foo => 'bar'});
my $bool = $c->render(handler => 'something');
my $bool = $c->render('foo/index');
使用Mojolicious中的renderer渲染内容,并在Mojolicious中先后触发before_render和after_render事件。接收的参数必须为键值对,它们会被合并到stash中。如果无法产生一个响应,则会调用Mojolicious::Plugin::DefaultHelpers中的reply->not_found 方法。
# Render characters
$c->render(text => 'I ? Mojolicious!');
# Render characters (alternative)
$c->stash(text => 'I ? Mojolicious!')->render;
# Render binary data
use Mojo::JSON 'encode_json';
$c->render(data => encode_json({test => 'I ? Mojolicious!'}));
# Render JSON
$c->render(json => {test => 'I ? Mojolicious!'});
# Render inline template
$c->render(inline => '<%= 1 + 1 %>');
# Render template "foo/bar.html.ep"
$c->render(template => 'foo/bar', format => 'html', handler => 'ep');
# Render template "test.*.*" with arbitrary values "foo" and "bar"
$c->render(template => 'test', foo => 'test', bar => 23);
# Render template "test.xml.*"
$c->render(template => 'test', format => 'xml');
# Render template "test.xml.*" (alternative)
$c->render('test', format => 'xml');
render_later
$c = $c->render_later;
禁用自动渲染以延迟响应生成,只有在自动渲染会导致发送“响应”时才需要。
# Delayed rendering
$c->render_later;
Mojo::IOLoop->timer(2 => sub {
$c->render(text => 'Delayed by 2 seconds!');
});
render_maybe
my $bool = $c->render_maybe;
my $bool = $c->render_maybe(foo => 'bar', baz => 23);
my $bool = $c->render_maybe('foo/index', format => 'html');
尝试呈现内容,如果无法产生一个响应,也不会调用Mojolicious::Plugin::DefaultHelpers中的reply->not_found 方法。并且使用与render完全相同的参数。
# Render template "index_local" only if it exists
$c->render_maybe('index_local') or $c->render('index');
render_to_string
my $output = $c->render_to_string('foo/index', format => 'pdf');
尝试渲染内容并将生成的内容包装成Mojo::BtyeStream对象返回,如果渲染失败,则返回undef。所有参数都将自动从本地获取,并且仅在此渲染操作期间可用。使用与“render”相同的参数。
# Render inline template
my $two = $c->render_to_string(inline => '<%= 1 + 1 %>');
rendered
$c = $c->rendered;
$c = $c->rendered(302);
在Mojolicious中完成响应,并触发after_dispatch的hook。默认使用200响应代码。
# Custom response
$c->res->headers->content_type('text/plain');
$c->res->body('Hello World!');
$c->rendered(200);
req
my $req = $c->req;
从tx中获取Mojo::Message::Request对象。
# Longer version
my $req = $c->tx->req;
# Extract request information
my $method = $c->req->method;
my $url = $c->req->url->to_abs;
my $info = $c->req->url->to_abs->userinfo;
my $host = $c->req->url->to_abs->host;
my $agent = $c->req->headers->user_agent;
my $custom = $c->req->headers->header('Custom-Header');
my $bytes = $c->req->body;
my $str = $c->req->text;
my $hash = $c->req->params->to_hash;
my $all = $c->req->uploads;
my $value = $c->req->json;
my $foo = $c->req->json('/23/foo');
my $dom = $c->req->dom;
my $bar = $c->req->dom('div.bar')->first->text;
res
my $res = $c->res;
从tx中获取Mojo::Message::Response对象。
# Longer version
my $res = $c->tx->res;
# Force file download by setting a response header
$c->res->headers->content_disposition('attachment; filename=foo.png;');
# Use a custom response header
$c->res->headers->header('Custom-Header' => 'whatever');
# Make sure response is cached correctly
$c->res->headers->cache_control('public, max-age=300');
$c->res->headers->append(Vary => 'Accept-Encoding');
respond_to
$c = $c->respond_to(
json => {json => {message => 'Welcome!'}},
html => {template => 'welcome'},
any => sub {...}
);
从Accept头、format存储或 GET/POST中的format参数中自动的选择最佳的内容响应格式。默认为Mojolicious::Renderer中的default_format或呈现空的204响应。
每种“内容类型”都可以使用一个回调函数或包含要传递给render方法的参数的哈希引用来处理。由于浏览器不会真正知道他们实际想要的是什么,所以在允许多种MIME类型的非特定的请求头Accept会被忽略,除非你使用X-Requested-With请求头在XMLHttpRequest类型的请求中进行了说明。
# Everything else than "json" and "xml" gets a 204 response
$c->respond_to(
json => sub { $c->render(json => {just => 'works'}) },
xml => {text => 'works '},
any => {data => '', status => 204}
);
对于更高级的内容协商逻辑,你可以使用Mojolicious::Plubin::DefaultHelpers中的accept方法来实现。
send
$c = $c->send({binary => $bytes});
$c = $c->send({text => $bytes});
$c = $c->send({json => {test => [1, 2, 3]}});
$c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]);
$c = $c->send($chars);
$c = $c->send($chars => sub {...});
通过WebSocket非阻塞的发送消息或WebSocket帧。如果传递了一个回调函数,则在所有数据定入后会被执行。此方法将自动响应具有101响应状态的WebSocket握手请求,以建立WebSocket连接。
# Send "Text" message
$c->send('I ? Mojolicious!');
# Send JSON object as "Text" message
$c->send({json => {test => 'I ? Mojolicious!'}});
# Send JSON object as "Binary" message
use Mojo::JSON 'encode_json';
$c->send({binary => encode_json({test => 'I ? Mojolicious!'})});
# Send "Ping" frame
use Mojo::WebSocket 'WS_PING';
$c->send([1, 0, 0, 0, WS_PING, 'Hello World!']);
# Make sure the first message has been written before continuing
$c->send('First message!' => sub {
my $c = shift;
$c->send('Second message!');
});
对于大多数空闲的WebSocket,您可能还需要在Mojolicious::Plubin::DefaultHelpers中设置inactiveivity_timeout(链接的在不活动时的等待时间),通常默认为15秒。
# Increase inactivity timeout for connection to 300 seconds
$c->inactivity_timeout(300);
session
my $session = $c->session;
my $foo = $c->session('foo');
$c = $c->session({foo => 'bar'});
$c = $c->session(foo => 'bar');
获取或替换session中的数据。所有会话数据通过Mojo::JSON进行序列化,然后后进行Base64编码,再执行HMAC-SHA1进行签名,最后把签名结果放到cookie中,以防止篡改。cookie通常有一个4096字节(4KiB)的限制,具体取决于浏览器。
# Manipulate session
$c->session->{foo} = 'bar';
my $foo = $c->session->{foo};
delete $c->session->{foo};
# Expiration date in seconds from now (persists between requests)
$c->session(expiration => 604800);
# Expiration date as absolute epoch time (only valid for one request)
$c->session(expires => time + 604800);
# Delete whole session by setting an expiration date in the past
$c->session(expires => 1);
signed_cookie
my $value = $c->signed_cookie('foo');
$c = $c->signed_cookie(foo => 'bar');
$c = $c->signed_cookie(foo => 'bar', {path => '/'});
从“请求”中获取已经签名的cookie,或向“响应”中设置签名的cookie。如果有多个值共享一个名称,你将从这个方法中得到众值中的最后一个。你可以使用every_signed_cookie获取所有值。
Cookies使用HMAC-SHA1加密签名,以防止篡改,并且将会自动丢弃签名验证失败的cookie。
stash
my $hash = $c->stash;
my $foo = $c->stash('foo');
$c = $c->stash({foo => 'bar', baz => 23});
$c = $c->stash(foo => 'bar', baz => 23);
获取或设置为当前请求存储的非持久的数据,只能在当前请求中使用。可以使用Mojolicious中的defaults方法设置默认值。有些值具有特殊含义在此列出:action,app,cb,controller,data,extends,format,handler,inline,json,layout,namespace,path,status,template,text和variant。
注:具有mojo.*前缀的所有存储空间都保留供Mojolicious框架内部使用。
# Remove value
my $foo = delete $c->stash->{foo};
# Assign multiple values at once
$c->stash(foo => 'test', bar => 23);
url_for
my $url = $c->url_for;
my $url = $c->url_for(name => 'sebastian');
my $url = $c->url_for({name => 'sebastian'});
my $url = $c->url_for('test', name => 'sebastian');
my $url = $c->url_for('test', {name => 'sebastian'});
my $url = $c->url_for('/index.html');
my $url = $c->url_for('//example.com/index.html');
my $url = $c->url_for('http://example.com/index.html');
my $url = $c->url_for('mailto:[email protected]');
my $url = $c->url_for('#whatever');
使用当前应用程序的信息(如:base、path、URL、route)生成一个便携的Mojo::URL对象。
# "http://127.0.0.1:3000/index.html" if application was started with Morbo
$c->url_for('/index.html')->to_abs;
# "https://127.0.0.1:443/index.html" if application was started with Morbo
$c->url_for('/index.html')->to_abs->scheme('https')->port(443);
# "/index.html?foo=bar" if application is deployed under "/"
$c->url_for('/index.html')->query(foo => 'bar');
# "/myapp/index.html?foo=bar" if application is deployed under "/myapp"
$c->url_for('/index.html')->query(foo => 'bar');
你还可以使用Mojolicious::Plugin::DefaultHelpers中的url_with从当前请求继承查询参数。
# "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1"
$c->url_with->query([page => 2]);
validation
my $validation = $c->validation;
获取 Mojolicious::Validator::Validation对象,用于验证当前请求中的一些信息。如:文件上传,GET或POST中的参数等。
注:“请求体”每个Parts 都需要加载到内存中被解析,所以需要确保它不会太大。默认情况下限制为16MiB。
# Validate GET/POST parameter
my $validation = $c->validation;
$validation->required('title', 'trim')->size(3, 50);
my $title = $validation->param('title');
# Validate file upload
my $validation = $c->validation;
$validation->required('tarball')->upload->size(1, 1048576);
my $tarball = $validation->param('tarball');
write
$c = $c->write;
$c = $c->write('');
$c = $c->write($bytes);
$c = $c->write($bytes => sub {...});
非阻塞地向响应中写入动态内容,如果参数中有回调函数,将在内容写完后执行。如果在调用此方法时没有传入一个数据库,则会处理并完成响应头,且允许稍候再写入动态内容。
# Keep connection alive (with Content-Length header)
$c->res->headers->content_length(6);
$c->write('Hel' => sub {
my $c = shift;
$c->write('lo!');
});
# Close connection when finished (without Content-Length header)
$c->write('Hel' => sub {
my $c = shift;
$c->write('lo!' => sub {
my $c = shift;
$c->finish;
});
});
你可以随时调用finish方法或写入空的数据空来结束响应流。
HTTP/1.1 200 OK
Date: Sat, 13 Sep 2014 16:48:29 GMT
Content-Length: 6
Server: Mojolicious (Perl)
Hello!
HTTP/1.1 200 OK
Connection: close
Date: Sat, 13 Sep 2014 16:48:29 GMT
Server: Mojolicious (Perl)
Hello!
对于长轮询,你还需要通过Mojolicious::Plugin::DefaultHelpers中的inactivity_timeout来增加连接在非活动状态的保持时间,默认值为15秒。
# Increase inactivity timeout for connection to 300 seconds
$c->inactivity_timeout(300);
write_chunk
$c = $c->write_chunk;
$c = $c->write_chunk('');
$c = $c->write_chunk($bytes);
$c = $c->write_chunk($bytes => sub {...});
使用分场传输的编码方式非阻塞的向响应中写入动态内容。如果参数中有回调函数,将在内容写完后执行。如果在调用此方法时没有传入一个数据库,则会处理并完成响应头,且允许稍候再写入动态内容。
# Make sure previous chunk has been written before continuing
$c->write_chunk('H' => sub {
my $c = shift;
$c->write_chunk('ell' => sub {
my $c = shift;
$c->finish('o!');
});
});
你可以随时调用finish方法或写入空的数据空来结束响应流。
HTTP/1.1 200 OK
Date: Sat, 13 Sep 2014 16:48:29 GMT
Transfer-Encoding: chunked
Server: Mojolicious (Perl)
1
H
3
ell
2
o!
0
AUTOLOAD
除了上述的属性和方法外,你还可以在Mojolicious::Controller对象上调用由app提供的helpers。这包括Mojolicious::Plugin::DefaultHelpers和Mojolicious::Plugin::TagHelpers中的所有helpers。
# Call helpers
$c->layout('green');
$c->title('Welcome!');
# Longer version
$c->helpers->layout('green');