Решён
Как вернуть ошибку на PHP и отловить ее на фронте?

Старый Пыховик PHP
3.4k
7

Пишу простой REST API на чистом PHP (без фреймворков, PHP 8.2). Нужно чтобы при ошибке (например, неверные данные в запросе или что то пошло не так в логике) бэк возвращал JSON с описанием ошибки, а не HTML-страницу с Whoops или просто пустой ответ.

На фронте (vanilla JS, fetch API) нужно это поймать и показать пользователю нормальное сообщение.

Как правильно организовать возврат ошибки на PHP и отловить ее на фронте? Как обрабатывать исключения и HTTP-коды?

Решение
74
Участник • 1 ответ

Базовая схема на PHP:

header('Content-Type: application/json');

set_exception_handler(function (Throwable $e) {
    http_response_code(500);
    echo json_encode([
        'error' => true,
        'message' => $e->getMessage(),
        'code' => $e->getCode()
    ]);
    exit;
});

// Для валидации входных данных бросаешь исключение вручную:
if (empty($_POST['email'])) {
    http_response_code(422);
    echo json_encode(['error' => true, 'message' => 'Email обязателен']);
    exit;
}

На фронте:

fetch('/api/endpoint', { method: 'POST', body: formData })
  .then(res => {
    if (!res.ok) {
      return res.json().then(err => Promise.reject(err));
    }
    return res.json();
  })
  .then(data => console.log('OK', data))
  .catch(err => alert(err.message ?? 'Что то пошло не так'));

Ключ в том что fetch не бросает ошибку на 4xx/5xx сам по себе - надо проверять res.ok вручную.

Аватар Старый Пыховик

Спасибо! Ключевой момент про res.ok пропустил в документации, из за этого и не работало.

41
Участник • 1 ответ

Добавлю к ответу выше - в начале файла убедись что выключен вывод HTML-ошибок:

ini_set('display_errors', 0);
error_reporting(E_ALL);

Иначе при фатальной ошибке PHP выплюнет HTML прямо перед JSON, сломает парсинг на фронте и будешь час чесать голову почему JSON.parse падает.

Аватар Старый Пыховик

Вот это именно то на чем я три часа потерял. Спасибо что добавил.

28
Эксперт • 3 ответа

Используй правильные HTTP-коды ответа:

400 - Bad Request (кривые данные от клиента)
401 - Unauthorized (не авторизован)
403 - Forbidden (нет прав)
404 - Not Found
422 - Unprocessable Entity (данные пришли, но не прошли валидацию)
500 - Internal Server Error (твоя ошибка на бэке)

Многие новички шлют 200 с {"error": true} в теле - это антипаттерн, ломает кэширование и семантику протокола.

19
Участник • 3 ответа

Раз уж без фреймворка - заверни это в минимальный класс:

class ApiResponse {
    public static function error(string $msg, int $code = 400): void {
        http_response_code($code);
        header('Content-Type: application/json');
        echo json_encode(['ok' => false, 'error' => $msg]);
        exit;
    }
    public static function success(mixed $data): void {
        header('Content-Type: application/json');
        echo json_encode(['ok' => true, 'data' => $data]);
        exit;
    }
}

// Использование:
ApiResponse::error('Email обязателен', 422);
ApiResponse::success(['id' => 42]);

Потом когда перейдешь на фреймворк - этот класс просто выкидываешь, ничего не сломается.

3
Участник • 4 ответа

А зачем чистый PHP в 2026 году? Возьми Slim Framework или даже Laravel - там все это уже сделано из коробки, middleware для обработки исключений, автоматические JSON-ответы. Не изобретай велосипед.

2
Участник • 1 ответ

по-моему на фронте еще можно сделать что то типа глобального перехватчика ошибок через window.onerror или через обертку над fetch... точно не помню как именно но гугли "axios interceptors" - там идея понятна, можно адаптировать под нативный fetch

9
Участник • 1 ответ

Если вдруг используешь output buffering где то в коде - это тоже источник боли. Любой echo до установки заголовков ломает весь JSON. Заголовки устанавливай первым делом, до любого вывода.

Написать ответ

Премодерация гостей

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

Будьте вежливы и соблюдайте правила платформы.