curl завершился успешно после HTTP 500: сохраняем тело ошибки и код отказа

Проверка API скачала JSON с описанием внутренней ошибки, но вызывающая программа считает операцию успешной. С точки зрения curl передача действительно могла завершиться нормально: соединение установлено, HTTP-ответ получен полностью. Код 500 описывает результат HTTP-операции, а не обязательно ошибку транспорта.

Разделите HTTP-статус и завершение процесса

curl -sS -o response.json -w 'http=%{http_code}\n' https://api.example/report

Такой вызов сохраняет тело и печатает HTTP-код. При ответе 500 он по умолчанию может закончиться нулевым кодом процесса. Поэтому проверка только кода завершения не видит отказ приложения. И обратная ошибка возможна: при недоступном сервере HTTP-ответа вообще не будет, хотя программа всё равно должна обработать неуспех.

Не ищите слово error в теле вместо статуса. Успешный ответ может содержать такое поле как обычные данные, а ошибочный быть пустым или HTML-страницей прокси. Для выбора дальнейшего действия нужны транспортный результат, HTTP-статус и содержимое, каждое на своём месте.

Включите отказ с сохранением тела

curl --fail-with-body --connect-timeout 5 --max-time 20 -sS -o response.json -D response.headers -w 'http=%{http_code}\n' https://api.example/report

fail-with-body доступен начиная с curl 7.76.0. При HTTP-ответах от 400 он позволяет вернуть ненулевой результат и сохранить тело. Старый fail обычно подавляет тело таких ответов, поэтому полезное описание проблемы теряется. Версию установленного клиента проверьте через curl --version.

Если сервер вернул 503 с JSON и Retry-After, тело окажется в response.json, заголовки — отдельно, а процесс сообщит об HTTP-ошибке кодом 22. Таймаут или ошибка TLS дадут другие коды. Вызывающая система должна сохранять эти различия, чтобы не объявить сетевую проблему бизнес-отказом API.

Определите успех конкретной операции

Статус 202 означает принятие задачи, но не её завершение. Ответ 204 успешно не содержит тела. Перенаправление 302 не превращается автоматически в нужный JSON, если вы не следуете Location. Поэтому окончательное условие успеха задаётся контрактом эндпоинта: допустимый статус, обязательные поля и, при необходимости, последующее получение результата.

Не включайте повторы для любого неуспеха одной общей опцией. Запрос создания отчёта или платежа мог уже изменить состояние до обрыва ответа. Для безопасного повторения нужны свойства операции и предусмотренный сервером идентификатор идемпотентности, если он поддерживается.

Проверьте настройку на управляемом стенде с успешным ответом, HTTP-ошибкой и транспортной ошибкой. Убедитесь, что потребитель не читает старый response.json как свежий результат после неудачного запуска. Для каждой операции используйте отдельные выходные файлы или очищайте результат в рамках контролируемого процесса.

Свяжите автоматизацию с проверкой реального результата. Откройте программу Linux и Bash для DevOps-инженеров. В ней есть HTTP-диагностика и скрипты с проверкой ошибок: это продолжение для задач, где успешный запуск команды ещё не означает выполненную операцию.

Ещё по теме

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.