Yii2 rest api обработка ошибок

Обработка ошибок ¶

Если при обработке запроса к RESTful API в запросе пользователя обнаруживается ошибка или происходит
что-то непредвиденное на сервере, вы можете просто выбрасывать исключение, чтобы уведомить пользователя о нештатной ситуации.
Если вы можете установить конкретную причину ошибки (например, запрошенный ресурс не существует), вам следует подумать
о том, чтобы выбрасывать исключение с соответствующим кодом состояния HTTP (например, yiiwebNotFoundHttpException,
соответствующее коду состояния 404). Yii отправит ответ с соответствующим
HTTP-кодом и текстом. Он также включит в тело ответа сериализованное представление
исключения. Например:

HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "name": "Not Found Exception",
    "message": "The requested resource was not found.",
    "code": 0,
    "status": 404
}

Сводный список кодов состояния HTTP, используемых REST-фреймворком Yii:

  • 200: OK. Все сработало именно так, как и ожидалось.
  • 201: Ресурс был успешно создан в ответ на POST-запрос. Заголовок Location
    содержит URL, указывающий на только что созданный ресурс.
  • 204: Запрос обработан успешно, и в ответе нет содержимого (для запроса DELETE, например).
  • 304: Ресурс не изменялся. Можно использовать закэшированную версию.
  • 400: Неверный запрос. Может быть связано с разнообразными проблемами на стороне пользователя, такими как неверные JSON-данные
    в теле запроса, неправильные параметры действия, и т.д.
  • 401: Аутентификация завершилась неудачно.
  • 403: Аутентифицированному пользователю не разрешен доступ к указанной точке входа API.
  • 404: Запрошенный ресурс не существует.
  • 405: Метод не поддерживается. Сверьтесь со списком поддерживаемых HTTP-методов в заголовке Allow.
  • 415: Не поддерживаемый тип данных. Запрашивается неправильный тип данных или номер версии.
  • 422: Проверка данных завершилась неудачно (в ответе на POST-запрос, например). Подробные сообщения об ошибках смотрите в теле ответа.
  • 429: Слишком много запросов. Запрос отклонен из-за превышения ограничения частоты запросов.
  • 500: Внутренняя ошибка сервера. Возможная причина — ошибки в самой программе.

Свой формат ответа с ошибкой ¶

Вам может понадобиться изменить формат ответа с ошибкой. Например, вместо использования разных статусов ответа HTTP
для разных ошибок, вы можете всегда отдавать статус 200, а реальный код статуса отдавать как часть JSON ответа:

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "success": false,
    "data": {
        "name": "Not Found Exception",
        "message": "The requested resource was not found.",
        "code": 0,
        "status": 404
    }
}

Для этого можно использовать событие beforeSend компонента response прямо в конфигурации приложения:

return [
    // ...
    'components' => [
        'response' => [
            'class' => 'yiiwebResponse',
            'on beforeSend' => function ($event) {
                $response = $event->sender;
                if ($response->data !== null && !empty(Yii::$app->request->get('suppress_response_code'))) {
                    $response->data = [
                        'success' => $response->isSuccessful,
                        'data' => $response->data,
                    ];
                    $response->statusCode = 200;
                }
            },
        ],
    ],
];

Приведённый выше код изменит формат ответа (как для удачного запроса, так и для ошибок) если передан GET-параметр
suppress_response_code.

When handling a RESTful API request, if there is an error in the user request or if something unexpected
happens on the server, you may simply throw an exception to notify the user that something went wrong.
If you can identify the cause of the error (e.g., the requested resource does not exist), you should
consider throwing an exception along with a proper HTTP status code (e.g., [[yiiwebNotFoundHttpException]]
represents a 404 status code). Yii will send the response along with the corresponding HTTP status
code and text. Yii will also include the serialized representation of the
exception in the response body. For example:

HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/7.1.0 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "name": "Not Found Exception",
    "message": "The requested resource was not found.",
    "code": 0,
    "status": 404
}

The following list summarizes the HTTP status codes that are used by the Yii REST framework:

  • 200: OK. Everything worked as expected.
  • 201: A resource was successfully created in response to a POST request. The Location header
    contains the URL pointing to the newly created resource.
  • 204: The request was handled successfully and the response contains no body content (like a DELETE request).
  • 304: The resource was not modified. You can use the cached version.
  • 400: Bad request. This could be caused by various actions by the user, such as providing invalid JSON
    data in the request body, providing invalid action parameters, etc.
  • 401: Authentication failed.
  • 403: The authenticated user is not allowed to access the specified API endpoint.
  • 404: The requested resource does not exist.
  • 405: Method not allowed. Please check the Allow header for the allowed HTTP methods.
  • 415: Unsupported media type. The requested content type or version number is invalid.
  • 422: Data validation failed (in response to a POST request, for example). Please check the response body for detailed error messages.
  • 429: Too many requests. The request was rejected due to rate limiting.
  • 500: Internal server error. This could be caused by internal program errors.

Customizing Error Response

Sometimes you may want to customize the default error response format. For example, instead of relying on
using different HTTP statuses to indicate different errors, you would like to always use 200 as HTTP status
and enclose the actual HTTP status code as part of the JSON structure in the response, like shown in the following,

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/7.1.0 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "success": false,
    "data": {
        "name": "Not Found Exception",
        "message": "The requested resource was not found.",
        "code": 0,
        "status": 404
    }
}

To achieve this goal, you can respond to the beforeSend event of the response component in the application configuration:

return [
    // ...
    'components' => [
        'response' => [
            '__class' => yiiwebResponse::class,
            'on beforeSend' => function ($event) {
                $response = $event->sender;
                if ($response->data !== null && Yii::$app->request->get('suppress_response_code')) {
                    $response->data = [
                        'success' => $response->isSuccessful,
                        'data' => $response->data,
                    ];
                    $response->statusCode = 200;
                }
            },
        ],
    ],
];

The above code will reformat the response (for both successful and failed responses) as explained when
suppress_response_code is passed as a GET parameter.

How to set a REST API error handler, when API used as a module.
I’m getting an invalid 404 found exception in HTML response rather than a json/xml response.

this is the sample api URL with an invalid entry point

http://localhost.backend.com/api/v1/invalidentrypoint

here api is in a module and v1 in nested with api module.

the reponse is

Not Found (#404)
Unable to resolve the request «api/v1/invalidentrypoint».
The above error occurred while the Web server was processing your request.
Please contact us if you think this is a server error. Thank you.

I’m expecting a response like

**HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked

Content-Type: application/json; charset=UTF-8
{
«type»: «yiiwebNotFoundHttpException»,
«name»: «Not Found Exception»,
«message»: «The requested resource was not found.»,
«code»: 0,
«status»: 404
}**

please help.

Всем привет! Прошу прощения, если тема повторялась!
Я строю REST, мне обходимо перехватывать ошибки yii, например при не верно авторизации, при неверной аутентификации.
У меня есть свой RestController, который имеет два метода success и failure. Значения их понятны.

Код: Выделить всё

  public function success($message = 'Ok', $data = [], $success = true){
        $result = [
            'success' => $success,
            'message' => $message,
            'data' => $data,
            'token' => $this->getNewToken()
        ];
        }
        
          public function failure($message = '', $data = [], $success = false){

        $result = [
            'success' => $success,
            'message' => $message,
            'data' => $data,
            'token' => $this->getNewToken()
        ];

        if(!YII_DEBUG){
            unset($result['message']);
        }

        return $result;
    }

При успешном выполнении запроса я делаю return $this->success, при неудачном $this->failure.
Но, если например юзер не прошел авторизацию, то yii выкидывает Exception и HTTP код ошибки (вроде) 401.

Как мне отдавать свои success и failure вместо yii Exception?

Спасибо!

Последний раз редактировалось t3mnikov 2017.02.16, 10:10, всего редактировалось 2 раза.

Время на прочтение
3 мин

Количество просмотров 34K

В Yii2 по-умолчанию все Exception обрабатываются, за это отвечает специальный обработчик. Если при обработке запроса возникает нехорошая ситуация (например, пришли некорректные данные от клиента), то можно выбросить исключение. Обработчик сформирует человекообразный ответ.

Интересно, что в таком случае ошибка “Warning: Uncaught exception” в лог ошибок не выводится. Может создаться впечатление, что все исключения перехватываются средствами фреймворка. Но это не так. На наш проект некоторое время назад натравили средство мониторинга (в нашем случае New Relic), которое информацию обо всех выброшенных исключениях отображает в ошибках (именно как “Warning: Uncaught exception”), считает эти исключения необработанными. С этим надо было что-то делать.

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

Почему обработанные исключения считаются не пойманными

В Yii2 обработчик ошибок задается функцией set_exception_handler(). Эта функция определяет обработчик для не пойманных исключений. При этом исключения хоть и обрабатываются, но остаются-таки не пойманными. Чтобы исключения считались пойманными, их все равно надо явно ловить, оборачивая вызовы в try-catch. В каждом экшне каждого контроллера делать этого очень не хотелось. Я считаю удобным иметь единую точку перехвата.

В Yii2, как оказалось, для этого есть готовый вариант — если выбросить исключение yiibaseExitException (или потомка от него), то такое исключение обрабатывается средствами фреймворка. Для наглядности, вот как это сделано в Application::run():

 public function run()
    {
        try {

            $this->state = self::STATE_BEFORE_REQUEST;
            $this->trigger(self::EVENT_BEFORE_REQUEST);

            $this->state = self::STATE_HANDLING_REQUEST;
            $response = $this->handleRequest($this->getRequest());

            $this->state = self::STATE_AFTER_REQUEST;
            $this->trigger(self::EVENT_AFTER_REQUEST);

            $this->state = self::STATE_SENDING_RESPONSE;
            $response->send();

            $this->state = self::STATE_END;

            return $response->exitStatus;

        } catch (ExitException $e) {

            $this->end($e->statusCode, isset($response) ? $response : null);
            return $e->statusCode;

        }
    }

“Хорошие” и “плохие” исключения

Мне удобно выбрасывать исключения с целью завершения обработки запроса в двух случаях.

  1. Если ничего не сломалось, просто имеет место мелкое недоразумение — пришел кривой веб-запрос на клиент или не нашлось каких-то не особо критичных запрашиваемых данных.
  2. Если что-то сломалось.

В первом случае не надо логировать событие как ошибку и разбираться с этим не надо.
Во втором случае надо логировать проблему, чтобы знать о случившемся и разбираться с проблемой.

Для первого случая я создал такой класс, унаследованный от yiibaseExitException. Чтобы результатом работы скрипта была не пустая страница, прямо в исключении генерируется ответ.

<?php

namespace appcomponents;

use yii;
use yiibaseExitException;

/**
 * Исключение, которое будет автоматически обрабатываться на уровне yiibaseApplication
 */
class GoodException extends ExitException
{
    /**
     * Конструктор
     * @param string $name Название (выведем в качестве названия страницы)
     * @param string $message Подробное сообщение об ошибке
     * @param int $code Код ошибки
     * @param int $status Статус ответа
     * @param Exception $previous Предыдущее исключение
     */
    public function __construct($name, $message = null, $code = 0, $status = 500, Exception $previous = null)
    {
        # Генерируем ответ
        $view = yii::$app->getView();
        $response = yii::$app->getResponse();
        $response->data = $view->renderFile('@app/views/exception.php', [
            'name' => $name,
            'message' => $message,
        ]);

        # Возвратим нужный статус (по-умолчанию отдадим 500-й)
        $response->setStatusCode($status);

        parent::__construct($status, $message, $code, $previous);
    }
}

А также создано еще представление.

<?php

/* @var $this yiiwebView */
/* @var $name string */
/* @var $message string */
/* @var $exception Exception */

use yiihelpersHtml;

$this->title = $name;
?>

<?php $this->beginContent('@app/views/layouts/main.php'); ?>
<div class="site-error">

    <h1><?= Html::encode($this->title) ?></h1>

    <div class="alert alert-danger">
        <?= nl2br(Html::encode($message)) ?>
    </div>

    <p>
        The above error occurred while the Web server was processing your request.
    </p>
    <p>
        Please contact us if you think this is a server error. Thank you.
    </p>

</div>
<?php $this->endContent(); ?>

Итого

Таким образом, чтобы выбросить “культурное” исключение, пишем:

# Выбрасываем исключение, которое будет поймано
throw new GoodException('Проблемка', 'Эта проблема аккуратно обрабатывается');

Такие исключения будут перехвачены и на клиент вернется аккуратный ответ. В лог ошибок такие события попадать не будут.

Все остальные исключения, если вы их явно не поймаете, ловиться не будут. И будут попадать в ошибки. Т.е. для второго случая можно писать

throw new yiibaseErrorException('Эта проблема критичная');
  1. Главная

  2. Туториалы

  3. Веб-программирование

  4. Yii

При обработке запроса API RESTful, если в запросе пользователя произошла ошибка или что-то неожиданное произошло на сервере, вы можете просто отправить исключение, чтобы уведомить пользователя о том, что что-то пошло не так. Если вы можете определить причину ошибки (например, запрошенный ресурс не существует), вам следует рассмотреть возможность исключения исключения вместе с соответствующим кодом состояния HTTP (например, yiiwebNotFoundHttpException представляет код состояния 404). Yii отправит ответ вместе с соответствующим кодом состояния и текстом HTTP. Yii также будет включать сериализованное представление исключения в теле ответа. Например:

HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "name": "Not Found Exception",
    "message": "The requested resource was not found.",
    "code": 0,
    "status": 404
}

В следующем списке приведены коды состояния HTTP, которые используются в инфраструктуре Yii REST:

  • 200: ОК. Все работало должным образом.
  • 201: Ресурс был успешно создан в ответ на запрос POST. Заголовок Location содержит URL-адрес, указывающий на только что созданный ресурс.
  • 204: запрос был обработан успешно, и ответ не содержит содержимого тела (например, запрос DELETE).
  • 304: Ресурс не был изменен. Вы можете использовать кэшированную версию.
  • ошибка 400, неверный запрос. Это может быть вызвано различными действиями пользователя, такими как предоставление недопустимых данных JSON в теле запроса, предоставление недопустимых параметров действия и т. д.
  • 401: Ошибка аутентификации.
  • 403: Уполномоченному пользователю не разрешен доступ к указанной конечной точке API.
  • 404: запрошенный ресурс не существует.
  • 405: Метод не разрешен. Проверьте заголовок Allow заголовки разрешенных методов HTTP.
  • 415: Неподдерживаемый тип носителя. Недопустимый запрошенный тип контента или номер версии.
  • 422: Ошибка проверки данных (например, в ответ на запрос POST). Пожалуйста, проверьте тело ответа на подробные сообщения об ошибках.
  • 429: Слишком много запросов. Запрос был отклонен из-за ограничения скорости.
  • 500 — внутренняя ошибка сервера. Это может быть вызвано внутренними ошибками программы.

Настройка ответа на ошибку

Иногда вы можете настроить формат ответа по умолчанию. Например, вместо того чтобы полагаться на использование разных HTTP-статусов для указания различных ошибок, вы всегда хотели бы использовать 200 как статус HTTP и приложить фактический код состояния HTTP как часть структуры JSON в ответе, как показано ниже,

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "success": false,
    "data": {
        "name": "Not Found Exception",
        "message": "The requested resource was not found.",
        "code": 0,
        "status": 404
    }
}

Для достижения этой цели вы можете ответить на событие beforeSend компонента ответа в конфигурации приложения:

return [
    // ...
    'components' => [
        'response' => [
            'class' => 'yiiwebResponse',
            'on beforeSend' => function ($event) {
                $response = $event->sender;
                if ($response->data !== null && Yii::$app->request->get('suppress_response_code')) {
                    $response->data = [
                        'success' => $response->isSuccessful,
                        'data' => $response->data,
                    ];
                    $response->statusCode = 200;
                }
            },
        ],
    ],
];

Вышеприведенный код будет переформатировать ответ (как для успешных, так и для неудавшихся ответов), как объясняется, когда параметр suppress_response_code передается как параметр GET.

Понравилась статья? Поделить с друзьями:

Не пропустите эти материалы по теме:

  • Яндекс еда ошибка привязки карты
  • Yii сообщение об ошибке
  • Yii показывать ошибки
  • Yii отображение ошибок
  • Yii обработка ошибок

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии