Как прочитать тело ответа при ошибке API с помощью curl?

Я разработал API, используя Slim v3, когда возникает исключение, у меня есть ErrorHandler, который возвращает следующее:

public function __invoke(Request $request, Response $response, \Exception $exception)
{
    $status = $exception->getCode() ? : 500;
    $error = [
        "status" => ERROR_MSG,
        "data" => [
            "stack_trace" => ($this->_container['settings']['displayErrorDetails']) ? $exception->getTraceAsString() : '',
        ],
        "message" => $exception->getMessage()
    ];

    $body = json_encode($error, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

    return $response
        ->withStatus($status)
        ->withHeader("Content-type", "application/json")
        ->write($body);
}

по сути, когда в API происходит исключение, например:

throw new Exception('Invalid user credentials');

API вернет этот ответ:

{
    "status": "error",
    "data": {
        "stack_trace": "some stack trace.."
    },
    "message": "Invalid user credentials"
}

теперь проблема в том, что когда я запускаю запрос с помощью curl, я получаю только:

string(59) "The requested URL returned error: 500 Internal Server Error"

из следующего кода:

curl_error($this->session);

где $this->session содержит запрос.

Я также попытался отладить запрос, используя:

$this->response = curl_exec($this->session);
$this->info = curl_getinfo($this->session);
$errno = curl_errno($this->session);
$error = curl_error($this->session);

и я получаю:

bool(false)
array(26) {
  ["url"]=>
  string(48) "http://localhost/ci3-api/v1/installation/install"
  ["content_type"]=>
  NULL
  ["http_code"]=>
  int(500)
  ["header_size"]=>
  int(0)
  ["request_size"]=>
  int(148)
  ["filetime"]=>
  int(-1)
  ["ssl_verify_result"]=>
  int(0)
  ["redirect_count"]=>
  int(0)
  ["total_time"]=>
  float(0.25)
  ["namelookup_time"]=>
  float(0.016)
  ["connect_time"]=>
  float(0.219)
  ["pretransfer_time"]=>
  float(0.219)
  ["size_upload"]=>
  float(0)
  ["size_download"]=>
  float(0)
  ["speed_download"]=>
  float(0)
  ["speed_upload"]=>
  float(0)
  ["download_content_length"]=>
  float(-1)
  ["upload_content_length"]=>
  float(0)
  ["starttransfer_time"]=>
  float(0.25)
  ["redirect_time"]=>
  float(0)
  ["redirect_url"]=>
  string(0) ""
  ["primary_ip"]=>
  string(9) "127.0.0.1"
  ["certinfo"]=>
  array(0) {
  }
  ["primary_port"]=>
  int(80)
  ["local_ip"]=>
  string(9) "127.0.0.1"
  ["local_port"]=>
  int(65036)
}
int(22)
string(59) "The requested URL returned error: 500 Internal Server Error"

как я могу прочитать ответное сообщение API? Кажется невозможным сделать это, когда ошибка 500 вызывается из API. Я пробовал с другими кодами ошибок, такими как 400, и я могу прочитать ответ, но с кодом ошибки 500 у меня всегда есть ответ false.

Это не сразу очевидно из вопроса, но является ли CURLOPT_RETURNTRANSFER правдой, а var_dump($this->response); является bool(false)? Кроме того, случайные предложения: отображение трассировки стека и сообщения об исключении может быть плохой идеей, если есть какие-либо необработанные исключения, которые не создаются вашим кодом. Кроме того, Invalid user credentials должен быть 401. Возможно, вы захотите создать специальное исключение, которое будет распознаваться обработчиком ошибок, и любые общие исключения должны просто возвращать общее сообщение об ошибке, а не сообщение об исключении.

drew010 29.07.2019 22:21

Для параметра CURLOPT_RETURNTRANSFER установлено значение true, и при возникновении исключения ответ всегда будет ложным. Я показываю трассировку стека только в процессе разработки, поэтому легко могу отладить запрос. Исключение выше, касающееся учетных данных, является просто примером. Итак, если я правильно понял, я должен возвращать код ошибки, который не равен 500, когда происходит исключение?

sfarzoso 29.07.2019 23:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
3
2
1 819
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

это моя установка; Я думаю, что важным для вас является CURLOPT_RETURNTRANSFER и в основном CURLOPT_FAILONERROR

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'your api url');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, false); // this is important for you I think

// other stuff you need to set

$output = curl_exec($ch);

$curlError = curl_error($ch);
$curlErrNo = curl_errno($ch);
$httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($output === false) {
// if header CURLOPT_FAILONERROR is true, always throw here
throw new RuntimeException('curl fail');
}

curl_close($ch);
// here process your output

Ключ в том, чтобы установить CURLOPT_FAILONERROR в false. У меня была такая же проблема с получением тела ответа от стороннего веб-сервиса, когда его код ответа http был >= 400, и это устранило проблему.

curl_setopt($ch, CURLOPT_FAILONERROR, false);

Другие вопросы по теме