Mojolicious模板渲染(十七)
一、后处理动态内容
虽然使用Mojolicious中的“after_dispatch”钩子后处理任务通常非常容易,但对于由渲染器生成的内容,使用Mojolicious中的“after_render”会更有效。
use Mojolicious::Lite -signatures;
use IO::Compress::Gzip qw(gzip);
hook after_render => sub ($c, $output, $format) {
#做一个渲染相关钩子
# 如果gzip已经设置为1,则返回
return unless $c->stash->{gzip};
# 如果user agent头接受gzip也返回
return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i;
$c->res->headers->append(Vary => 'Accept-Encoding');
# 用gzip对内容进行压缩
$c->res->headers->content_encoding('gzip');
gzip $output, \my $compressed;
$$output = $compressed;
};
get '/' => {template => 'hello', title => 'Hello', gzip => 1};
app->start;
__DATA__
@@ hello.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>Compressed content.</body>
</html>
如果我们想压缩所有动态生成的内容,也可以在Mojolicious::Renderer中激活“compress”。
二、二进制流
我们不必一次呈现所有内容,Mojolicious::Controller中的“write”方法也可以用来把呈现的内容分成一小块一小块的。
use Mojolicious::Lite -signatures;
get '/' => sub ($c) {
# 准备请求体
my $body = 'Hello World!';
$c->res->headers->content_length(length $body);
# 通过一个请求体来发送body
my $drain = sub ($c) {
my $chunk = substr $body, 0, 1, '';
$c->write($chunk, length $body ? __SUB__ : undef);
};
$c->$drain;
};
app->start;
每当整个之前的数据块实际被写入时,就会执行drain回调函数。
HTTP/1.1 200 OK
Date: Sat, 13 Sep 2014 16:48:29 GMT
Content-Length: 12
Server: Mojolicious (Perl)
Hello World!
除了提供一个content-length的头,我们还可以在Mojolicious::Controller中调用“finish”,完成后手动关闭连接:
use Mojolicious::Lite -signatures;
get '/' => sub ($c) {
# Prepare body
my $body = 'Hello World!';
# Start writing directly with a drain callback
my $drain = sub ($c) {
my $chunk = substr $body, 0, 1, '';
length $chunk ? $c->write($chunk, __SUB__) : $c->finish;
#调用finish结束
};
$c->$drain;
};
app->start;
虽然这是相当低效的。但因为它阻止了keep-alive,有时对于EventSource和类似的应用程序是必要的。
HTTP/1.1 200 OK
Date: Sat, 13 Sep 2014 16:48:29 GMT
Connection: close
Server: Mojolicious (Perl)
Hello World!