未找到Catalyst Template Toolkit模板返回404

时间:2013-05-22 16:02:19

标签: perl http-status-code-404 catalyst template-toolkit

我正在尝试为我的设计师创建一个非常灵活的Catalyst应用。我的意思是,如果他们需要添加一个包含静态内容的新页面,我就不必进入Catalyst并添加该操作,然后才能为页面创建模板。我有它,所以如果他们添加任何名为name.html的模板,那么即使没有Catalyst操作,http://www.domain.com/name.html应用也可以显示name。目前我在Root控制器中有一个子程序,如下所示:

sub any_template :Regex('(.+)\.html$') { 
    my ($self, $c) = @_; 
    $c->stash(
        template => $c->action . '.html',
    );
}

这使得以“.html”结尾的任何请求都将按该名称查找模板。但是,如果为不存在的模板请求了一个url,Template Toolkit会抛出一个错误,说它无法呈现模板,这是有道理的,因为它不存在。但是,如果模板不存在,我希望能够显示我的404未找到的页面。是否有可能做到这一点?或者,是否有人有更好的方法可以将其设置到您可以拥有模板页面的位置而无需向Catalyst应用添加空操作?我知道可以使用perl的-e文件测试来查看文件系统上是否存在模板,但有没有更好的方法呢?谢谢!

更新

这是我当前的包装器的样子:

[% 
    debug("Applying HTML page layout wrappers to $template.name\n");
    content WRAPPER "$host/site/html" + "$host/site/layout";
-%]

这主要是由TTSite产生的。无论如何我可以做一些类似于RET建议的东西,如果失败我可以使用try catch块来使用404页面吗?

更新

我已经尝试将我的包装模板更新为:

[%- 
    TRY;
        content WRAPPER "$host/site/html" + "$host/site/layout"; 
    CATCH file;
        "File Error! $error.info";
    CATCH;
        "Error: $error.info!";
    END;
-%]

它会说找不到页面时会出现文件错误:

Couldn't render template test.html: file error - test.html: not found

然而,它不会进入我的任何一个拦截块。我应该把它放在别的地方吗?

更新

Template Toolkit文件说:

Note that the DEFAULT option (disabled by default) allows you to specify a default 
file to be used any time a template file can't be found. This will prevent file 
exceptions from ever being raised when a non-existant file is requested (unless,
of course, the DEFAULT file your specify doesn't exist). Errors encountered once 
the file has been found (i.e. read error, parse error) will be raised as file 
exceptions as per usual.

这正是我正在寻找的,但没有如何使用它的例子。有谁知道如何使用DEFAULT选项?

3 个答案:

答案 0 :(得分:1)

您可能根本不需要使用Catalyst来获取静态内容。通常,静态内容(如图像,CSS,Javascript)由您的Web服务器(nginx或APache)直接提供。您可以对HTML静态文件执行相同的操作。

如果你真的想混合静态和动态内容,请查看Catalyst :: Plugin :: Static :: Simple] 1$c->serve_static_file($file_path)函数。

答案 1 :(得分:1)

我赞成Julien的答案,因为他完全正确 - 这是处理真正静态资源的最佳方式。如果它只是HTML,请让它们将它放在静态区域,并根据Web服务器的需要设置别名或位置记录。

但是,如果您的设计人员正在制作需要放在WRAPPER内或需要进行动态处理的模板,那么您很快就会遇到一些限制。

不是像这样直接处理模板,而是可以这样做:

=== Root.pm ===

sub any_template {
    ...
    $c->stash(template => 'static.tt');
}

=== static.tt ===

[%- WRAPPER foo.tt -%]
[%- SET tmpl = c.action;
    TRY;
        # use either PROCESS if a template, or INCLUDE if it's HTML
        PROCESS tmpl _ ".tt";
        # INCLUDE tmpl _ ".html"; # or this
    CATCH;
        PROCESS "404.tt";
    END -%]
[%- END -%]

以便正常处理文件未找到。使用404.tt模板意味着仍然会显示您的包装器的页眉/页脚等。

答案 2 :(得分:0)

所以我最终找到了一个允许我按照自己的意愿行事的解决方案。我没有使用默认的RenderView,而是创建了自己的:

#old end action
#sub end : ActionClass('RenderView') {}

sub end : Private { 
    my ($self, $c) = @_; 

    return if $c->res->body ne '';  

    my $output;
    eval { $output = $c->view($c->stash->{current_view})->render($c,$c->stash->{template})};

    unless($@) { 
        $c->res->body($output);
    }   
    else {
        $c->res->status(404);
        $c->stash->{template} = 'errors/404.html';
        $c->forward($c->view('NO_HTML'));
    }   
}

它可能有点hacky,但它做了我想要的,并允许我显示404页面以及每当找不到页面时404的响应,这使我能够保持不必的灵活性为我创建的每个模板定义一个动作。