Как настроить страницы ошибок

В приложениях Symfony все ошибки воспринимаются, как исключения, вне зависимости от того, являются ли они простой ошибкой 404 "Не найдено" или фатальной ошибкой, запущенной вызовом какого-то исключения в вашем коде.

В окружении разработки, Symfony ловит все исключения и отображаеть специальную страницу исключений со множеством информации по отладке, чтобы помочь вам быстро обнаружить основную проблему:

Типичная страница исключений в окружении разработки

Так как эти страницы содержат много чувствительной внутренней информации, Symfony не будет отображать её в окружении производства. Вместо этого, она покажет простую и общую ошибку страница ошибки:

Типичная страница ошибки в окружении производства

Страницы ошибок в окружении производства можно настроить разными способами, в зависимости от ваших потребностей:

  1. Если вы просто хотите изменить содержание и стили страниц ошибок так, чтобы они совпадали с остальным вашим приложением, переопределите шаблоны ошибок по умолчанию;
  2. Если вы также хотите настроить логику, используемую Symfony для генерирования ваших страниц ошибок, то переопределите контроллер исключений по умолчанию;
  3. Если вам нужен полный контроль над работой с исключениями, выполните вашу собственную логику - используйте событие the kernel.exception.

Переопределение шаблонов ошибок по умолчанию

Когда загружается страница ошибки, для отображения шаблона twig и демонастрации пользователю, используется внутренний ExceptionController.

Этот контроллер использует статус-код HTTP, формат запроса и следующую логику, чтобы определить имя файла шаблона:

  1. Ищите шаблон для заданного формата и статус-кода (вроде error404.json.twig или error500.html.twig);
  2. Если предыдущий шаблон не существует, отбросьте статус-код и ищите общий шаблон для заданного формата (вроде error.json.twig или error.xml.twig);
  3. Если не существует ни один из предыдущих шаблонов, используйте общий резеврный HTML-шаблон (error.html.twig).

Чтобы переопределить эти шаблоны, просто положитесь на стандартный метод Symfony для пеоепределения шаблонов, живущих внутри пакета: поместите их в каталоге templates/bundles/TwigBundle/Exception/.

Типичный проект, возвращающий страницы HTML и JSON, может выглядеть так:

1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
templates/
└─ bundles/
   └─ TwigBundle/
      └─ Exception/
         ├─ error404.html.twig
         ├─ error403.html.twig
         ├─ error.html.twig      # Все другие HTML ошибки (включая 500)
         ├─ error404.json.twig
         ├─ error403.json.twig
         └─ error.json.twig      # Все другие JSON ошибки (включая 500)

Пример шаблона ошибки 404

Чтобы переопределить шаблон ошибки 404 для HTML-страниц, создайте новый шаблон error404.html.twig, находящийся в templates/bundles/TwigBundle/Exception/:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{# templates/bundles/TwigBundle/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Page not found</h1>

    <p>
        Запрошенная страница не найдена. Проверьте опечатки в URL или
        <a href="{{ path('homepage') }}">вернитесь на домашнюю сраницу</a>.
    </p>
{% endblock %}

Если они вам понадобятся, ExceptionController передаёт некоторую информацию в шаблон ошибок через переменные status_code и status_text, которые хранят HTTP статус-код и сообщение соотвественно.

Tip

Вы можете настроить статус-код, реализовав HttpExceptionInterface и его обязательный метод getStatusCode(). В обратном случае, status_code по умолчанию будет``500``.

Note

Страницы исключений, отображающиеся в окружении разработки, можно настроить таким же образом, как страницы об ошибках. Создайте новый шаблон exception.html.twig для страницы стандартного HTML-исключния, или exception.json.twig для страницы JSON-исключения.

Тестирование страниц ошибок по время разработки

В то время, как вы находитесь в окружении разработки, Symfony отображает большую страницу исключений вместо вашей новой блестящей страницы ошибок. Так как вам увидеть, как она выглядит изнутри и отладить её?

К счастью, ExceptionController по умолчанию разрешает вам предпросмотр вашей страницы ошибки во время разработки.

Чтобы использовать эту функцию, вам загрузить специальные маршруты, предоставленные TwigBundle (если приложение использует Symfony Flex, то они загружаются автоматически при установке поддержки Twig):

  • YAML
    1
    2
    3
    4
    # config/routes/dev/twig.yaml
    _errors:
        resource: '@TwigBundle/Resources/config/routing/errors.xml'
        prefix:   /_error
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <!-- config/routes/dev/twig.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <routes xmlns="http://symfony.com/schema/routing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/routing
            http://symfony.com/schema/routing/routing-1.0.xsd">
    
        <import resource="@TwigBundle/Resources/config/routing/errors.xml"
            prefix="/_error" />
    </routes>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    // config/routes/dev/twig.php
    use Symfony\Component\Routing\RouteCollection;
    
    $collection = new RouteCollection();
    $collection->addCollection(
        $loader->import('@TwigBundle/Resources/config/routing/errors.xml')
    );
    $collection->addPrefix("/_error");
    
    return $collection;
    

C добавлением этого маршрута, вы можете использовать такие URL для предпросмотра страницы ошибки для заданного статус-кода в виде HTML или для заданного статус-кода и формата.

1
2
http://localhost/index.php/_error/{statusCode}
http://localhost/index.php/_error/{statusCode}.{format}

Переопределение ExceptionController по умолчаию

Если вам нужно немного больше гибкости кроме простого переопределения шаблона, то вы можете изменить контроллер, отображающий странцу ошибки. Например, вам может быть нужо передать дополнительные переменные в ваш шаблон.

Чтобы сделать это, просто создайте новый контролер где угодно в вашем приложении, и установите опцию конфигурации twig.exception_controller, чтобы указать на неё:

  • YAML
    1
    2
    3
    # config/packages/twig.yaml
    twig:
        exception_controller: App\Controller\ExceptionController::showException
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!-- config/packages/twig.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:twig="http://symfony.com/schema/dic/twig"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/twig
            http://symfony.com/schema/dic/twig/twig-1.0.xsd">
    
        <twig:config>
            <twig:exception-controller>App\Controller\ExceptionController::showException</twig:exception-controller>
        </twig:config>
    
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/packages/twig.php
    $container->loadFromExtension('twig', array(
        'exception_controller' => 'App\Controller\ExceptionController::showException',
        // ...
    ));
    

Класс ExceptionListener, используемый TwigBundle в качестве слушателя события kernel.exception, создаёт запрос, который будет развёрнут в вашем контроллере. В дополнение, вашему контроллеру будут переданы два параметра:

exception
Сущность FlattenException, создання их обрабатываемого исключения.
logger
Сущность DebugLoggerInterface, которая может в некоторых случаях быть null.

Вместо создания новго контроллера исключений с нуля, вы конечно же можете также расширить класс по умолчанию ExceptionController. В таком случасе, вы можете захотеть переопределить один или оба метода showAction() и findTemplate(). Последний содержит шаблон для использования.

Note

В случае расширения класса ExceptionController, вы можете сконфигурировать севис, чтобы передать окружению Twig и конструктору флага debug.

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    # config/services.yaml
    services:
        _defaults:
            # ... be sure autowiring is enabled
            autowire: true
        # ...
    
        App\Controller\CustomExceptionController:
            public: true
            arguments:
                $debug: '%kernel.debug%'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... be sure autowiring is enabled -->
            <defaults autowire="true" />
            <!-- ... -->
    
            <service id="App\Controller\CustomExceptionController" public="true">
                <argument key="$debug">%kernel.debug%</argument>
            </service>
        </services>
    
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // config/services.php
    use App\Controller\CustomExceptionController;
    
    $container->autowire(CustomExceptionController::class)
        ->setArgument('$debug', '%kernel.debug%');
    

Tip

Предпросмотр страницы ошибки также работает с вашими собственными контроллерами, нвстроенными как угодно.

Работа с событием kernel.exception

когда вызывается исключение, класс HttpKernel ловит его и развёртывает событие kernel.exception. Это даёт вам возможность конвертировать исключение в Response несколькими разными способами.

Работа с этим событием на самом деле значительн более мощная, чем объяснялось раньше, но также требует тщательного понимания внутренних процессов Symfony. Представьте, что ваш код вызывает специальные исключения с конкретным значением в вашем домене приложения.

Написание вашего собственного слушателя событий для события kernel.exception позволяет вам ближе рассмотретьисключение и предпринять по отношению к нему разные действия. Эти действия могут включать в себя запись лога исключения, перенаправление пользователя на другую страницу или отображение специальных страниц ошибки.

Note

Если ваш слушатель вызывает setResponse() в событии GetResponseForExceptionEvent, распространение будет остановлено и клиенту будет отправлен ответ.

Этот подход позволяет вам создавать централизованную и многослойную обработку ошибок: вместо того, чтобы ловить (и обрабатывать) одни и те же исключения в разных контроллерах снова и снова, вы просто можете иметь одного (или нескольких) слушателей, чтобы разбираться с ними.

Tip

Смотрите код класса ExceptionListener для реального примера продвинутого слушателя такого типа. Этот слушатель обрабатывает различные исключения, связанные с безопасностью, которые вызываются в вашем приложении (как AccessDeniedException) и предпринимает действия вроде перенаправления пользователей на страницу входа, выполняет их вход в систему и др.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.