TABLE OF CONTENTS

名称

Mojolicious::Controller - Controller 的基类

概述

# Controller
package MyApp::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::ControllerMojolicious 中的 controllers 的基类。它也是 Mojolicious 中默认的 controller 类.除非你在你的应用中自己设置了 controller_class

ATTRIBUTES

Mojolicious::Controller 是从 Mojo::Base 中继承了所有的属性。它自己实现了如下新的一些。

app

my $app = $c->app;
$c      = $c->app(Mojolicious->new);

这是应用回到调度的控制器上的引用。默认是 Mojolicious 的对象。

# Use application logger
$c->app->log->debug('Hello Mojo!');

match

my $m = $c->match;
$c    = $c->match(Mojolicious::Routes::Match->new);

为当前的请求进行路由, 默认是 Mojolicious::Routes::Match 对象。

# Introspect
my $foo = $c->match->endpoint->pattern->defaults->{foo};
my $bar = $c->match->stack->[-1]{bar};

tx

my $tx = $c->tx;
$c     = $c->tx(Mojo::Transaction::HTTP->new);

当前连接的处理程序, 通常是 Mojo::Transaction::HTTP 或者 Mojo::Transaction::WebSocket 的对象来实现的. 注意: 这个中取到的对象都是使用了 weaken 来进行了弱引用操作, 以防止循环数据结构造成的内存泄漏. 所以当你执行非阻塞操作和底层连接, 需要对象的引用在其它的地方还使用时, 这可能会引起过早关闭.

# Check peer information
my $address = $c->tx->remote_address;

# 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::ControllerMojo::Base 中继承了全部的方法, 并扩展了如下新的。

my $value  = $c->cookie('foo');
my @values = $c->cookie('foo');
$c         = $c->cookie(foo => 'bar');
$c         = $c->cookie(foo => 'bar', {path => '/'});

访问请求中传过来的 cookie 的值和创建新的响应的 cookies.

# Create response cookie with domain
$c->cookie(name => 'sebastian', {domain => 'mojolicio.us'});

finish

$c = $c->finish;
$c = $c->finish('Bye!');

优雅地结束 WebSocket 的连接或 long poll 长轮询流.

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);

on

my $cb = $c->on(finish => sub {...});

tx 中订阅相关的事件回调, 这会影响的是 Mojo::Transaction::HTTPMojo::Transaction::WebSocket 的对象上的事件. 注意, 这个方法会自动的使用 101 的响应状态做为 WebSocket 的握手请求回应.

# 在传送完成之后做一些操作. 
$c->on(finish => sub {
  my $c = shift;
  $c->app->log->debug('We are done!');
});

# Receive WebSocket message
$c->on(message => sub {
  my ($c, $msg) = @_;
  $c->app->log->debug("Message: $msg");
});

# 在 WebSocket 中接收 JSON 对象的信息
$c->on(json => sub {
  my ($c, $hash) = @_;
  $c->app->log->debug("Test: $hash->{test}");
});

# 接收 WebSocket 的 "Binary" 二进制信息
$c->on(binary => sub {
  my ($c, $bytes) = @_;
  my $len = length $bytes;
  $c->app->log->debug("Received $len bytes.");
});

param

my @names       = $c->param;
my $foo         = $c->param('foo');
my @foo         = $c->param('foo');
my ($foo, $bar) = $c->param(['foo', 'bar']);
$c              = $c->param(foo => 'ba;r');
$c              = $c->param(foo => qw(ba;r ba;z));
$c              = $c->param(foo => ['ba;r', 'baz']);

访问 GET/POST, 文件上传的内容和 route 中占位符取的内容的参数. 这些参数从请求 url 的字符和 "application/x-www-form-urlencoded" or "multipart/form-data" 的 body 中按顺序取得. 注意, 此方法是在某些情况下, 上下文敏感的, 并因此需要小心使用. 参数可以有多个值, 这可能会带来意想不到的后果. 这个要求如果请求的 body 是象 "multipart/form-data" 必须不能过大, 因为这部分 body 需要加载到内存中来解析 post 的参数, 这个默认值是不能超过 10M 的限制.

# List context is ambiguous and should be avoided you can get multiple
# values returned for a query string like "?foo=bar&foo=baz&foo=yada"
my $hash = {foo => $self->param('foo')};

# Better enforce scalar context
my $hash = {foo => scalar $self->param('foo')};

# The multi name form can also enforce scalar context
my $hash = {foo => $self->param(['foo'])};

为了更好的控制, 你也可以直接访问请求信息。

# Only GET parameters
my $foo = $c->req->url->query->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');
$c = $c->redirect_to('named', foo => 'bar');
$c = $c->redirect_to('/path');
$c = $c->redirect_to('http://127.0.0.1/foo/bar');

准备一个 302 重定向的响应, 这个有一些扩展的参数, 和 url_for 一样的参数 .

# Conditional redirect
return $c->redirect_to('login') unless $c->session('user');

# Moved permanently
$c->res->code(301);
$c->redirect_to('some_route');

render

my $success = $c->render;
my $success = $c->render(controller => 'foo', action => 'bar');
my $success = $c->render({controller => 'foo', action => 'bar'});
my $success = $c->render(template => 'foo/index');
my $success = $c->render(template => 'index', format => 'html');
my $success = $c->render(data => $bytes);
my $success = $c->render(text => 'Hello!');
my $success = $c->render(json => {foo => 'bar'});
my $success = $c->render(handler => 'something');
my $success = $c->render('foo/index');
my $output  = $c->render('foo/index', partial => 1);

使用 "render" in Mojolicious::Renderer 渲染内容。如果没有提供模板的名字会基于请求的路径和动作来生成。全部的值会合并到 stash.

render_data

$c->render_data($bytes);
$c->render_data($bytes, format => 'png');

渲染给定的内容, 类似 render_text 但不会进行编码,数据以原始字节生成。所有的值会合并到stash中。

# Longer version
$c->render(data => $bytes);

render_exception

$c->render_exception('Oops!');
$c->render_exception(Mojo::Exception->new('Oops!'));

渲染出错时的 exception 模板 exception.$mode.$format.* or exception.$format.* 然后设置响应状态为 500

render_json

$c->render_json({foo => 'bar'});
$c->render_json([1, 2, -3], status => 201);

渲染结果成 JSON 的数据结构, 所有数据会合到 stash.

# Longer version
$c->render(json => {foo => 'bar'});

render_later

$c = $c->render_later;

禁用自动渲染生成内容, 来延迟 HTTP 的响应生成的时机, 只要有必要的时候才会生成响应.大多用在异步的时候.

# Delayed rendering
$c->render_later;
Mojo::IOLoop->timer(2 => sub {
  $c->render(text => 'Delayed by 2 seconds!');
});

render_not_found

$c->render_not_found;

渲染不存在的 not found 模板 not_found.$mode.$format.* or not_found.$format.* 并设置状态码为 404.

render_partial

my $output = $c->render_partial('menubar');
my $output = $c->render_partial('menubar', format => 'txt');
my $output = $c->render_partial(template => 'menubar');

render 但返回渲染结果。

# Longer version
my $output = $c->render('menubar', partial => 1);

render_static

my $success = $c->render_static('images/logo.png');
my $success = $c->render_static('../lib/MyApp.pm');

渲染一个静态的的文件使用 "serve" in Mojolicious::Static, 通常从 public 的目录或 DATA 的部分, 你的应用程序。请注意, 此方法的目录。

render_text

$c->render_text('Hello World!');
$c->render_text('Hello World!', layout => 'green');

渲染的如Perl字符的内容, 这将被编码成字节。所有的值会合并到 stash 中。是 render_data 的替代品, 无需进行编码。需要注意的是这并没有改变响应的内容类型, 默认情况下, 这是 text/html;charset=UTF-8

# Longer version
$c->render(text => 'Hello World!');

# Render "text/plain" response
$c->render_text('Hello World!', format => 'txt');

rendered

$c = $c->rendered;
$c = $c->rendered(302);

最后的响应状态和使用 after_dispatch 插件的 hook 点, 默认使用 200 的响应状态码。

# Stream content directly from file
$c->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
$c->res->headers->content_type('text/plain');
$c->rendered(200);

req

my $req = $c->req;

取得 Mojo::Message::Request 的对象从 "req" in Mojo::Transaction.

# Longer version
my $req = $c->tx->req;

# Extract request information
my $userinfo = $c->req->url->userinfo;
my $agent    = $c->req->headers->user_agent;
my $body     = $c->req->body;
my $foo      = $c->req->json('/23/foo');
my $bar      = $c->req->dom('div.bar')->first->text;

res

my $res = $c->res;

取得 Mojo::Message::Response 的对象从 "res" in Mojo::Transaction.

# Longer version
my $res = $c->tx->res;

# Force file download by setting a custom response header
$c->res->headers->content_disposition('attachment; filename=foo.png;');

respond_to

$c->respond_to(
  json => {json => {message => 'Welcome!'}},
  html => {template => 'welcome'},
  any  => sub {...}
);

Accept 请求头中选择最好的资源回应, format 的 stash 值或者 format 中的 GET/POST 的参数。

默认使用一个空的 204 的响应。如果 Accept 的请求头中包含多过一个 MIME 的类型会被忽略.因为浏览器通知不知道这个的意思。

$c->respond_to(
  json => sub { $c->render_json({just => 'works'}) },
  xml  => {text => '<just>works</just>'},
  any  => {data => '', status => 204}
);

send

$c = $c->send({binary => $bytes});
$c = $c->send({text   => $bytes});
$c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
$c = $c->send($chars);
$c = $c->send($chars => sub {...});

发送消息或通过 WebSocket 的无阻塞框架, 在这个中的 drain 回调函数会被调用一次当所有的数据都被写入时。

# Send "Text" frame
$c->send('Hello World!');

# Send JSON object as "Text" frame
$c->send({text => Mojo::JSON->new->encode({hello => 'world'})});

# Send JSON object as "Binary" frame
$c->send({binary => Mojo::JSON->new->encode({hello => 'world'})});

# Send "Ping" frame
$c->send([1, 0, 0, 0, 9, 'Hello World!']);

空闲的 WebSockets 的超时, 你可能还需要增加闲置逾时, 通常默认为 15 秒。

# Increase inactivity timeout for connection to 300 seconds
Mojo::IOLoop->stream($c->tx->connection)->timeout(300);

session

my $session = $c->session;
my $foo     = $c->session('foo');
$c          = $c->session({foo => 'bar'});
$c          = $c->session(foo => 'bar');

持久性数据存储, 所有的会话数据 通过 Mojo::JSON 序列化和存储在 HMAC-SHA1 签署 cookies。需要注意的是 Cookies 通常中 4096 个字节的限制, 取决于你使用什么浏览器。

# Manipulate session
$c->session->{foo} = 'bar';
my $foo = $c->session->{foo};
delete $c->session->{foo};

# Expiration date in epoch 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);
my $value  = $c->signed_cookie('foo');
my @values = $c->signed_cookie('foo');
my ($foo, $bar) = $c->signed_cookie(['foo', 'bar']);
$c         = $c->signed_cookie(foo => 'bar');
$c         = $c->signed_cookie(foo => 'bar', {path => '/'});

访问签名的请求 cookie 的值, 并创建新的签名响应 cookie。 cookie 失败时 HMAC-SHA1 签名验证将被自动删除。

stash

my $stash = $c->stash;
my $foo   = $c->stash('foo');
$c        = $c->stash({foo => 'bar'});
$c        = $c->stash(foo => 'bar');

这个用来做非持久性数据存储和交换, 这个的默认值可以设置 "defaults" in Mojolicious。 有许多藏匿的值有特殊的含义, 是保留的, 目前完整的列表是 action, app, cb, controller, data, extends, format, handler, json, layout, namespace, partial, path, status, template and text. Note that all stash values with a mojo.* prefix are reserved for internal use.

# Remove value
# my $foo = delete $c->stash->{foo};

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('/perldoc');
my $url = $c->url_for('//mojolicio.us/perldoc');
my $url = $c->url_for('http://mojolicio.us/perldoc');
my $url = $c->url_for('mailto:sri@example.com');

生成可移植的 Mojo::URL 对象的 route , 路径或 URL。

# "http://127.0.0.1:3000/perldoc" if application has been started with Morbo
# $c->url_for('/perldoc')->to_abs;

# "/perldoc?foo=bar" if application is deployed under "/"
$c->url_for('/perldoc')->query(foo => 'bar');

# "/myapp/perldoc?foo=bar" if application is deployed under "/myapp"
$c->url_for('/perldoc')->query(foo => 'bar');

您也可以使用辅助性 helper "url_with" in Mojolicious::Plugin::DefaultHelpers 来从当前请求中继承请求的参数

# "/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 对象, 这个是会检查 GETPOST 参数导入到这个中, 参数是从查询字符和 application/x-www-form-urlencodedmultipart/form-data 的信息中取得. 如果是 multipart/form-data 之类的信息, 这需要都加载到内存中解析这个 POST 参数, 所以这个不能处理很大的文件, 这是限制为 10M 的默认.

my $validation = $c->validation;
$validation->required('title')->size(3, 50);
my $title = $validation->param('title');

write

$c = $c->write;
$c = $c->write($bytes);
$c = $c->write(sub {...});
$c = $c->write($bytes => sub {...});

非阻塞写动态的内容, 选项 drain 的回调函数被调用时所有的数据都被写入。

# 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;
  });
});

在 Comet (long polling) 你可能需要通过 "inactivity_timeout" in Mojolicious::Plugin::DefaultHelpers 来增加闲置逾时, 通常默认为 15 秒。

# Increase inactivity timeout for connection to 300 seconds
Mojo::IOLoop->stream($c->tx->connection)->timeout(300);

write_chunk

$c = $c->write_chunk;
$c = $c->write_chunk('Hello!');
$c = $c->write_chunk(sub {...});
$c = $c->write_chunk('Hello!' => sub {...});

无阻塞的写入动态内容用来 chunked 传输编码, 当 drain 回调会被调用时所有数据已被写入。

# Make sure previous chunk has been written before continuing
$c->write_chunk('He' => sub {
  my $c = shift;
  $c->write_chunk('ll' => sub {
    my $c = shift;
    $c->finish('o!');
  });
});

你可以调用 finish 在任何的时候结束这个流.

2
He
2
ll
2
o!
0

帮助

除了上面的属性和方法, 你可以使用 Mojolicious::Controller 的对象。在 Mojolicious::Plugin::DefaultHelpers"Mojolicious:: Plugin::TagHelpers" 包含全部的 helpers

$c->layout('green');
$c->title('Welcome!');

SEE ALSO

Mojolicious, Mojolicious::Guides, http://mojolicio.us.