Yii2: создаем свой обработчик ошибок

Совсем недавно, при реализации одного проекта на Yii2, столкнулся с проблемой подключения собственного обработчика ошибок. Проблема была в том, что мало того, что этого не удавалось сделать налету, так еще и задание класса обработчика из конфига не давало эффекта, т.к. alias @app не регистрируется на тот момент в приложении.

Этой проблеме были посвящены 2 репорта на гитхабе, кому интересно можно посмотреть тут  и тут

Я же хочу здесь резюмировать свой опыт и показать а как же все таки реализовать переопределение обработчика ошибок.

Задача передо мной стояла в добавлении мета-информации и форматированию структуры ответа об ошибке. Стандартный вариант мне не подходил. Надо так же упомянуть, что обработчик нужен был только для конкретного модуля, реализующего доступ к API приложения (на базе REST-компонентов Yii2), а значит никаких вьюшек, ответ нужен был в JSON формате.

Первое, что я сделал, это создал папку components в своем API-модуле. В ней я определил класс, наследующих от стандартного \yii\web\ErrorHandler. Идея состояла в том, чтобы формировать ответ с Exception’ом в виде массива, а далее REST-контроллер сам отформатирует это в JSON (такова логика работы REST-контроллеров в Yii2 “из коробки”). Получился такой обработчик:

 

Все хорошо, но подключение обработчика тоже требует каких-то действий. Вот тут у меня возникла загвоздка, что как раз и привело к двум репортам на гитхабе. К счастью, это очень оперативно пофиксили и для своих нужд в init методе модуля API я переопределил обработчика ошибок

Если бы в моем приложении было только REST API, я бы скорее всего определил бы обработчик глобально прямо в конфиге, например так:

На этом в общем-то все. В итоге я стал получать ответы об ошибках в нужном для обработке на клиенте формате.

3 комментария Yii2: создаем свой обработчик ошибок

  1. Alex

    Ваш код для меня хорошо подходил для форматирования вывода ошибки, но при этом обнаружилось несколько проблем:
    1.) при ошибке 404 по неизвестному url yii2 отказывался проходить через модуль
    2.) после указания конкретного actionError для errorHandler компонента, оно начало заходить в наш action но опять таки здесь ваш ApiErrorHandler был не удел.

    Все решилось прозаично просто – добавлением в конфиг(у меня api реализовано как отдельное приложение по принципу yii advanced application) для компонента response, параметра ‘format’ => ‘json’

    А от вашего ApiErrorHandler пришлось совсем увы отказаться так-как почему-то при ошибке 404 выдает теперь стандартный для AcitveController json который возможно изменить только через ‘on beforeSend’ для компонента response.

    Я с yii 1.1 перешел вот на днях и возможно чего-то еще не знаю, возможно найду нормальное решение в будущем. Для интересующихся вот так теперь выглядит у меня полностью конфиг для компонента response:

    ‘response’ => [
    ‘class’ => ‘yii\web\Response’,
    ‘format’ => ‘json’,
    ‘on beforeSend’ => function ($event) {
    $response = $event->sender;
    if ($response->data !== null && isset($response->data['code']) && isset($response->data['status']) && isset($response->data['type'])) {
    unset($response->data['code'],$response->data['type']);
    }
    }
    ],

  2. АнтонАнтон

    На самом деле странно, что у вас при указании стороннего обработчика через конфиг в случае 404-ой возникает что-то в обход него. Сложно что-либо посоветовать, не видя конкретного кода и ситуации. Могу только сказать, что стоит еще раз все перепроверить, ведь при замене обработчика по сути нет ни какой разницы какого рода ошибка (404, 403 или что-то другое), в работу все равно должен вступать ваш обработчик.

    Манипуляция с format действительно может помочь, но опять таки, если речь идет о работе стандартной версии обработчика.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">