自定义404在Laravel 4.2与布局


Custom 404 in Laravel 4.2 with Layout

我的页面使用全局布局,许多视图都有自己的控制器使用这种布局。控制器动作调用的视图如下:

class NewsController extends BaseController {
  protected $layout = 'layouts.master';
  public function index()
  {
    $news = News::getNewsAll();
    $this->layout->content = View::make('news.index', array(
        'news' => $news
    ));
  }
}

我想以同样的方式创建一个自定义404页面,因为我需要嵌套自定义404设计的正常页面布局。有可能吗?问题是,我无法从控制器将HTTP状态代码设置为404,所以它只是一个软-404。我知道正确的方法是在App::missing()中从filter.php发送Response::view('errors.404', array(), 404),但我不能仅在视图中设置布局,这是不够的。还是我错了,而且这是可能的?

谢谢!

更新:我已经用我在项目中使用的文件为这个问题创建了一个Gist。也许了解我目前的状态更有帮助。

这是我的方法。只需将以下代码添加到/app/start/global.php文件

App::missing(function($exception)
{
    $layout = 'View::make('layouts.error');
    $layout->content = 'View::make('views.errors.404');
    return Response::make($layout, 404);
});

您可以通过在global.php上添加类似的内容并创建必要的错误视图来完成此操作。

App::error(function(Exception $exception, $code)
{
    $pathInfo = Request::getPathInfo();
    $message = $exception->getMessage() ?: 'Exception';
    Log::error("$code - $message @ $pathInfo'r'n$exception");
    if (Config::get('app.debug')) {
        return;
    }
    switch ($code)
    {
        case 403:
            return Response::view( 'error/403', compact('message'), 403);
        case 500:
            return Response::view('error/500', compact('message'), 500);
        default:
            return Response::view('error/404', compact('message'), $code);
    }
});

你也可以查看一些可用的laravel入门套件包,看看它们是如何做到这一点的。这是我的laravel管理模板版本

我不能告诉你这是最好的方法还是被认为是最好的实践,但和你一样,我很沮丧,在Illuminate''Routing''Controller中使用callAction方法找到了另一种解决方案。

app/start/global.php

App::missing(function($exception)
{
    return App::make("ErrorController")->callAction("missing", []);
});

app/controllers/ErrorController.php

<?php
class ErrorController extends BaseController {
    protected $layout = 'layouts.master';
    public function missing()
    {
        $this->layout->content = View::make('errors.missing');
    }
}

希望它能有所帮助!

我知道我迟到了,但由于这个问题仍然没有得到回答,并且在查询的搜索结果中排名相对较高,"Laravel 404异常处理程序错误"。只是因为这个SO页面仍然是一个常见的问题,并且没有标记的解决方案,我想为许多用户添加更多信息和另一个可能的解决方案。

当你按照这里和其他地方提供的方法,使用app/start/global.php文件来实现app:error()时,应该注意的是,base_controller是在这个文件之后实例化的,所以你可能传递到普通视图文件(例如$user)中的任何变量都不会被设置。如果在您扩展的模板中引用了这些变量中的任何一个,则会出现错误。

如果重新访问视图文件并检查变量是否使用isset()设置,并通过设置默认值来处理false条件,则仍然可以扩展模板。

例如;

@yield('styles')
<style type="text/css">
body{
    background-color: {{ $user->settings->bg_color }};
}
</style>

上面的操作将抛出报告的错误,因为执行此操作时没有$user对象。通常的异常处理程序会提供更多的细节,但为了实际显示404页面,这是不必要的,所以你几乎没有什么可以继续的。然而,如果你使用isset()或empty(),你可以适应这种情况。

<style type="text/css">
body{
    @if(isset($user))
        background-color: {{ $user->settings->bg_color }};
    @else
        background-color: #FFCCFF;
    @endif
}
</style>

如果在顶级布局或头文件中有大量引用,那么这个简单的解决方案没有帮助。您可能需要将@extends从核心布局更改为自定义布局。例如,视图/布局/错误。叶片.php。

然后在你的404.blade.php中,你会做这样的

@extends('layouts.errors')

并使用不依赖$user(或其他)的新标题创建视图/layouts/errors.blade.php。

希望能有所帮助。

我在这个问题上挠头了一会儿,下面是解决方案:

In-app/start/global.php:

App::error(function(Exception $exception, $code) {
    if ($exception instanceof 'Symfony'Component'HttpKernel'Exception'NotFoundHttpException) {
      Log::error('NotFoundHttpException Route: ' . Request::url() );
    }
    Log::error($exception);
    // HTML output on staging and production only
    if (!Config::get('app.debug'))
        return App::make("ErrorsController")->callAction("error", ['code'=>$code]);
});

注意:以上代码段仅在调试模式为true的环境中显示这些自定义错误页。在相应的app.php文件中设置各种环境的调试模式:http://laravel.com/docs/4.2/configuration#environment-配置)

In-app/controller/ErrorsController.php:

protected $layout = "layouts.main";
/*
|--------------------------------------------------------------------------
| Errors Controller
|--------------------------------------------------------------------------
*/
public function error($code) {
    switch ($code) {
        case 404:
            $this->layout->content = View::make('errors.404');
        break;
        default:
            $this->layout->content = View::make('errors.500');
        break;
    }
}

}

注意:protected$layout="layouts.main";指的是我的主布局,它被命名为"main"。您的主布局可能被命名为其他名称,例如"master"。)

最后,创建app/views/errors/404.blade.php和app/views/errors/500.blade.php,并在其中放置您想要的错误页面HTML。它将自动包装在layouts.main中!

缺少页面和500个内部错误现在将自动显示带有布局的自定义错误页面。您可以手动从任何控制器调用错误页面,方法是:return App::make("ErrorsController")->callAction("error", ['code'=>404]);(用您想要的任何错误代码替换404)

404.blade.php的顶部,您可以扩展主布局@extends('layouts.master')

好吧,这就是实现目标的方法(根据需要进行修改)。

App::error(function(Symfony'Component'HttpKernel'Exception'NotFoundHttpException $exception, $code) use ($path, $referer, $ip)
{
    // Log the exception
    Log::error($exception);
    // This is a custom model that logs the 404 in the database (so I can manage redirects etc within my app)
    ErrorPage::create(['destination_page' => $path, 'referer' => $referer, 'ip' => $ip]);
    // Return a response for the master layout
    $layout = Response::view('layouts.frontend');
    // Instantiate your error controller and run the required action/method, make sure to return a response from the action
    $view = App::make('Namespace'Controllers'Frontend'ErrorsController')->notFound();
    // Merge data from both views from the responses into a single array
    $data = array_merge($layout->original->getData(), $view->original->getData());
    // There appears to be a bug (at least in Laravel 4.2.11) where,
    // the response will always return a 200 HTTP status code, so
    // set the status code here.
    http_response_code(404);
    // Return your custom 404 error response view and pass the required data and status code.
    // Make sure your error view extends your master layout.
    return Response::view('404', $data, 404);
});

因此,我们在这里所做的基本上是为主布局和自定义404/error视图返回一个响应,然后从这些响应的视图对象中检索数据,将数据组合到一个数组中,然后返回一个回应,并传递我们的自定义404/eerror视图、数据和HTTP状态代码。

注意:出现了一个错误(至少在Laravel 4.2.11中),无论您传递给view()或make()什么,响应都将始终返回200 HTTP状态代码。话虽如此,您需要使用http_response_code手动设置响应代码(404)。