Есть ответы
Как вернуть ошибку на PHP и отловить ее на фронте?

Старый Пыховик PHP
487
5

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

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

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

41
Участник • 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 пропустил в документации, из за этого и не работало.

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

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

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

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

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

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

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

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

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

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

10
Участник • 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]);

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

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

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

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

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

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

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