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

В приложениях 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 для пеоепределения шаблонов, живущих внутри пакета: поместите их в каталоге app/Resources/TwigBundle/views/Exception/.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
app/
└─ Resources/
   └─ TwigBundle/
      └─ views/
         └─ 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, находящийся в app/Resources/TwigBundle/views/Exception/:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{# app/Resources/TwigBundle/views/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Страница не найдена</h1>

    {% if is_granted('IS_AUTHENTICATED_FULLY') %}
        {# ... #}
    {% endif %}

    <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 по умолчанию разрешает вам предпросмотр вашей страницы ошибки во время разработки.

Чтобы использовать эту функцию, вам нужно иметь определение в вашем файле routing_dev.yml, выглядящее таким образом:

  • YAML
    1
    2
    3
    4
    # app/config/routing_dev.yml
    _errors:
        resource: "@TwigBundle/Resources/config/routing/errors.xml"
        prefix:   /_error
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <!-- app/config/routing_dev.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
    // app/config/routing_dev.php
    use Symfony\Component\Routing\RouteCollection;
    
    $collection = new RouteCollection();
    $collection->addCollection(
        $loader->import('@TwigBundle/Resources/config/routing/errors.xml')
    );
    $collection->addPrefix("/_error");
    
    return $collection;
    

Если вы пользуетесь более старой версией Symfony, то вам может понадобиться добавить это routing_dev.yml в ваш файл. Если вы начинаете с нуля, то Symfony Standard Edition уже содержит это для вас..

С этим добавленным маршрутом, вы можете использовать URL вроде:

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

Чтобы получить предпросмотр страницы ошибок для данного статуса HTML-кода или для данного статус-кода и формата.

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

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

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

  • YAML
    1
    2
    3
    # app/config/config.yml
    twig:
        exception_controller: AppBundle:Exception:showException
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!-- app/config/config.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>AppBundle:Exception:showException</twig:exception-controller>
        </twig:config>
    
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // app/config/config.php
    $container->loadFromExtension('twig', array(
        'exception_controller' => 'AppBundle:Exception: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
    # app/config/services.yml
    services:
        _defaults:
            # ... убедитесь, что включено автомонтирование
            autowire: true
        # ...
    
        AppBundle\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
    <!-- app/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>
            <!-- ... убедитесь, что включено автомонтирование -->
            <по умолчанию, autowire="true" ... />
            <!-- ... -->
    
            <service id="AppBundle\Controller\CustomExceptionController" public="true">
                <argument key="$debug">%kernel.debug%</argument>
            </service>
        </services>
    
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    // app/config/services.php
    use AppBundle\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.