В приложениях Symfony все ошибки рассматриваются как исключения Exception, независимо от того, являются ли они просто ошибкой 404 Not Found или фатальной ошибкой, вызванной возникновением некоторого исключения в вашем коде.
В среде разработки Symfony перехватывает все исключения и отображает специальную страницу исключений со множеством отладочной информации, которая поможет вам обнаружить корневую проблему:
Поскольку такие страницы содержат много конфиденциальной внутренней информации, Symfony не будет отображать их в production среде. Вместо этого он покажет простую и общую страницу ошибок:
Страницы ошибок для production среды могут быть настроены по-разному в зависимости от ваших потребностей:
- Если вы просто хотите изменить содержимое и стили страниц ошибок, чтобы они соответствовали остальной части вашего приложения, переопределите шаблоны ошибок по умолчанию;
- Если вы хотите изменить содержимое вывода ошибок, отличных от HTML, создайте новый нормализатор;
- Если вы также хотите настроить логику, используемую Symfony для генерации страниц ошибок, переопределите контроллер ошибок по умолчанию;
- Если вам нужен полный контроль над обработкой исключений для выполнения вашей собственной логики, используйте событие kernel.exception.
Как переопределить шаблон страницы ошибок по умолчанию?
Вы можете использовать встроенный обработчик ошибок Twig, чтобы переопределить шаблоны ошибок по умолчанию. Для этого должны быть установлены как TwigBundle, так и TwigBridge. Запустите эту команду, чтобы убедиться, что оба установлены:
composer require twig
Когда страница ошибки загружается, TwigErrorRenderer используется для визуализации шаблона Twig для отображения пользователю.
Этот рендерер использует код состояния HTTP и следующую логику для определения имени файла шаблона:
- Находится шаблон для данного кода состояния (например, error500.html.twig);
- Если предыдущий шаблон не существует, то игнорируется код состояния и находится общий шаблон ошибки (error.html.twig).
Чтобы переопределить эти шаблоны, используйте стандартный метод Symfony для переопределения шаблонов, которые находятся внутри пакета, и поместите их в каталог templates/bundles/TwigBundle/Exception/.
Типичный проект, который возвращает HTML-страницы, может выглядеть так:
templates/
└─ bundles/
└─ TwigBundle/
└─ Exception/
├─ error404.html.twig
├─ error403.html.twig
└─ error.html.twig # All other HTML errors (including 500)
Пример 404 Шаблона ошибки
Чтобы переопределить шаблон ошибки 404 для страниц HTML, создайте новый шаблон error404.html.twig, расположенный в шаблонах /bundles/TwigBundle/Exception /:
{# templates/bundles/TwigBundle/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<h1>Page not found</h1>
<p>
The requested page couldn't be located. Checkout for any URL
misspelling or <a href="{{ path('homepage') }}">return to the homepage</a>.
</p>
{% endblock %}
Если вам потребуется, TwigErrorRenderer передает некоторую информацию в шаблон ошибки через переменные status_code и status_text, которые хранят код состояния HTTP и сообщение соответственно.
Вы можете настроить код состояния исключения, реализовав HttpExceptionInterface и его обязательный метод getStatusCode(). В противном случае код_состояния по умолчанию будет равен 500.
Тестирование страниц ошибок в режиме develop.
Пока вы находитесь в среде develop, Symfony показывает большую страницу исключений вместо вашей новой блестящей настраиваемой страницы ошибок. Итак, как вы можете увидеть, как это выглядит и отладить его?
К счастью, ErrorController по умолчанию позволяет вам просматривать страницы ошибок во время разработки.
Чтобы использовать эту функцию, вам нужно загрузить некоторые специальные маршруты, предоставляемые FrameworkBundle (если приложение использует Symfony Flex, они загружаются автоматически при установке symfony/framework-bundle):
# config/routes/dev/framework.yaml
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error
После добавления этого маршрута вы можете использовать подобные URL-адреса для предварительного просмотра страницы ошибки для заданного кода состояния в виде HTML или для заданного кода состояния и формата.
http://localhost/index.php/_error/{statusCode}
http://localhost/index.php/_error/{statusCode}.{format}
Переопределение вывода ошибок для не-HTML форматов.
Чтобы переопределить вывод ошибок, в формате отличном от HTML, необходимо установить компонент Serializer.
composer require serializer
Компонент Serializer имеет встроенный нормализатор FlattenException (ProblemNormalizer) и енкодеры JSON / XML / CSV / YAML. Когда ваше приложение выдает исключение, Symfony может вывести его в одном из этих форматов. Если вы хотите изменить содержимое вывода, создайте новый нормализатор, который поддерживает вход FlattenException:
# src/App/Serializer/MyCustomProblemNormalizer.php
namespace App\Serializer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class MyCustomProblemNormalizer implements NormalizerInterface
{
public function normalize($exception, string $format = null, array $context = [])
{
return [
'content' => 'This is my custom problem normalizer.',
'exception'=> [
'message' => $exception->getMessage(),
'code' => $exception->getStatusCode(),
],
];
}
public function supportsNormalization($data, string $format = null)
{
return $data instanceof FlattenException;
}
}
Переопределение стандартного ErrorController.
Если вам нужно немного больше гибкости, чем просто переопределение шаблона, вы можете изменить контроллер, отображающий страницу с ошибкой. Например, вам может потребоваться передать некоторые дополнительные переменные в ваш шаблон.
Для этого создайте новый контроллер в любом месте вашего приложения и установите параметр конфигурации framework.error_controller, чтобы он указывал на него:
# config/packages/framework.yaml
framework:
error_controller: App\Controller\ErrorController::showAction
Класс ErrorListener, используемый FrameworkBundle в качестве прослушивателя события kernel.exception, создает запрос, который будет отправлен вашему контроллеру. Кроме того, вашему контроллеру будут переданы два параметра:
- exception — Экземпляр FlattenException, созданный из обрабатываемого исключения.
- logger — Экземпляр DebugLoggerInterface, который может быть null в некоторых случаях.
Вместо создания нового контроллера исключений с нуля вы также можете расширить ExceptionController по умолчанию. В этом случае вы можете переопределить один или оба метода showAction() и findTemplate(). Последний находит шаблон для использования.
В случае расширения ExceptionController вы можете настроить сервис для передачи окружения Twig и флага отладки в конструктор.
# config/services.yaml
services:
_defaults:
# ... be sure autowiring is enabled
autowire: true
# ...
App\Controller\CustomExceptionController:
public: true
arguments:
$debug: '%kernel.debug%'
Работа с событием kernel.exception
Когда бросается exception, класс HttpKernel перехватывает его и отправляет событие kernel.exception. Это дает вам возможность преобразовать исключение в ответ несколькими различными способами.
Работа с этим событием на самом деле намного эффективнее, чем было объяснено ранее, но также требует глубокого понимания внутренних возможностей Symfony. Предположим, что ваш код выдает специализированные исключения с особым значением в область вашего приложения.
Написание собственного слушателя событий для события kernel.exception позволяет вам ближе рассмотреть исключение и предпринять различные действия в зависимости от него. Эти действия могут включать логирование исключения, редирект пользователя на другую страницу или отображение специализированных страниц с ошибками.
Если ваш слушатель вызывает setResponse() для ExceptionEvent, событие, дальнейшая обработка другими слушателями будет остановлено, и ответ будет отправлен клиенту.
Этот подход позволяет вам создавать централизованную и многоуровневую обработку ошибок: вместо того, чтобы снова и снова перехватывать (и обрабатывать) одни и те же исключения в различных контроллерах, вы можете иметь дело только с одним (или несколькими) слушателями.