如何在Mojolicious中为403页面渲染自定义模板?
如何让Mojolicious路由条件触发的403使用自定义模板?
我编写了一个用于检查当前用户是否有权访问URL的函数,并通过add_condition将其附加到路由,具体代码如下:
use Mojolicious::Lite; # Adding a custom condition app->routes->add_condition(auth => sub { my ($route, $c, $captures, $num) = @_; $c->res->code(403); $c->rendered(403); # Here, you could define your condition. For example, check if a parameter is set. return 0; # true/false depending on parameter }); my $r = app->routes; $r->get('/block')->requires(auth => 1)->to(cb => sub { my $c = shift; $c->render(template => 'default'); }); # Route for home get '/' => sub { my $c = shift; $c->render(template => 'main'); }; # Default template app->start; __DATA__ @@ 403.html.ep <!DOCTYPE html> <html> <head><title>Default Template</title></head> <body> <h1>Welcome to the Default Template</h1> <p>This is the default template.</p> </body> </html> @@ main.html.ep <!DOCTYPE html> <html> <head><title>Main page</title></head> <body> <h1>Welcome to the main page</h1> <p>The main page is here.</p> </body> </html>
当前访问http://127.0.0.1:3000/block会返回带有403状态码的空白页面,而访问http://127.0.0.1:3000/可正常渲染主页。请问我该如何配置才能为403页面使用自定义模板?
问题原因
你在路由条件里调用了$c->rendered(403),这个方法仅标记响应流程结束,但不会自动渲染对应状态码的模板,所以返回了空白页面。
解决方法
方法一:在路由条件中直接渲染403模板
修改auth条件的代码,去掉rendered(403),改用render方法指定模板和状态码,同时保留你的权限检查逻辑:
use Mojolicious::Lite; # 修改后的自定义条件 app->routes->add_condition(auth => sub { my ($route, $c, $captures, $num) = @_; # 这里替换为你的实际权限判断逻辑,比如检查session、请求参数等 my $has_permission = 0; # 示例:当前无权限 if (!$has_permission) { # 直接渲染自定义403模板,并设置状态码 $c->render(template => '403', status => 403); return 0; } return 1; }); my $r = app->routes; $r->get('/block')->requires(auth => 1)->to(cb => sub { my $c = shift; $c->render(template => 'default'); }); # Route for home get '/' => sub { my $c = shift; $c->render(template => 'main'); }; app->start; __DATA__ @@ 403.html.ep <!DOCTYPE html> <html> <head><title>403 访问被禁止</title></head> <body> <h1>403 Forbidden</h1> <p>你没有权限访问此页面,请检查你的权限设置。</p> </body> </html> @@ main.html.ep <!DOCTYPE html> <html> <head><title>Main page</title></head> <body> <h1>Welcome to the main page</h1> <p>The main page is here.</p> </body> </html>
方法二:全局统一处理403错误(推荐)
如果希望所有触发403状态码的请求都自动使用自定义模板,可以添加全局钩子,避免在每个路由条件里重复写渲染逻辑:
use Mojolicious::Lite; # 添加全局错误处理钩子 app->hook(after_render => sub { my ($c, $output, $format) = @_; # 当响应状态码为403且输出为空时,渲染自定义模板 if ($c->res->code == 403 && !$$output) { $c->render(template => '403', status => 403); } }); # 路由条件保持简洁,仅设置状态码和返回权限判断结果 app->routes->add_condition(auth => sub { my ($route, $c, $captures, $num) = @_; # 权限判断逻辑 my $has_permission = 0; if (!$has_permission) { $c->res->code(403); return 0; } return 1; }); my $r = app->routes; $r->get('/block')->requires(auth => 1)->to(cb => sub { my $c = shift; $c->render(template => 'default'); }); get '/' => sub { my $c = shift; $c->render(template => 'main'); }; app->start; __DATA__ @@ 403.html.ep <!DOCTYPE html> <html> <head><title>403 访问被禁止</title></head> <body> <h1>403 Forbidden</h1> <p>你没有权限访问此页面,请检查你的权限设置。</p> </body> </html> @@ main.html.ep <!DOCTYPE html> <html> <head><title>Main page</title></head> <body> <h1>Welcome to the main page</h1> <p>The main page is here.</p> </body> </html>
关键说明
$c->render()方法会自动完成模板渲染、状态码设置和响应发送,无需再调用rendered();- 方法一适合对特定路由的403页面做个性化定制;
- 方法二更适合全局统一处理所有403错误,减少重复代码。
内容的提问来源于stack exchange,提问作者user4035
相关产品推荐
相关产品推荐

