Mojolicious路由(十三)
一、条件
来自Mojolicious::Plugin::HeaderCondition的header、agent和host等条件可以应用于任何带有Mojolicious::Routes:: route方法“requires”的路由,并允许更强大的路由结构。
# / (Origin: http://perl.org)
$r->get('/')->requires(headers => {Origin => qr/perl\.org/})->to('foo#bar');
# / (Firefox)
$r->get('/')->requires(agent => qr/Firefox/)->to('browser-test#firefox');
# / (Internet Explorer)
$r->get('/')->requires(agent => qr/Internet Explorer/)->to('browser-test#ie');
# http://docs.mojolicious.org/Mojolicious
$r->get('/')->requires(host => 'docs.mojolicious.org')->to('perldoc#index');
请注意,对于路由缓存来说,条件太复杂了,路由缓存通常会加快重复请求的速度,因此会降低性能。
二、钩子
钩子在路由系统之外运行,允许我们通过Mojolicious中的“hook”与所有请求共享代码来扩展框架本身,这使它们成为一个非常强大的工具,特别是对于插件来说。
# Application
package MyApp;
use Mojo::Base 'Mojolicious', -signatures;
sub startup ($self) {
# Check all requests for a "/test" prefix
$self->hook(before_dispatch => sub ($c) {
$c->render(text => 'This request did not reach the router.') if $c->req->url->path->contains('/test');
});
# These will not be reached if the hook above renders a response
my $r = $self->routes;
$r->get('/welcome')->to('foo#welcome');
$r->post('/bye')->to('foo#bye');
}
1;
对响应进行后处理以添加或删除头是一种非常常见的用法。
# Make sure static files are cached
$app->hook(after_static => sub ($c) {
$c->res->headers->cache_control('max-age=3600, must-revalidate');
});
# Remove a default header
$app->hook(after_dispatch => sub ($c) {
$c->res->headers->remove('Server');
});
对请求的预处理也是一样的。
# Choose template variant based on request headers
$app->hook(before_dispatch => sub ($c) {
return unless my $agent = $c->req->headers->user_agent;
$c->stash(variant => 'ie') if $agent =~ /Internet Explorer/;
});
或更高级的扩展,以便向应用程序添加监视。
# Forward exceptions to a web service
$app->hook(after_dispatch => sub ($c) {
return unless my $e = $c->stash('exception');
$c->ua->post('https://example.com/bugs' => form => {exception => $e});
});
甚至可以扩展许多核心功能。
# Make controller object available to actions as $_
$app->hook(around_action => sub ($next, $c, $action, $last) {
local $_ = $c;
return $next->();
});
# Pass route name as argument to actions
$app->hook(around_action => sub ($next, $c, $action, $last) {
return $c->$action($c->current_route);
});
有关可用钩子的完整列表,请参阅Mojolicious中的“HOOKS”。