Могу ли я заставить cURL завершиться с ошибкой с кодом выхода, отличным от 0, если код состояния HTTP не равен 200?

Я всегда предполагал, что когда curl получил ответ HTTP 500, он возвращал код выхода, который означал сбой (!= 0), но, похоже, это не так.

Есть ли способ, как я могу сделать сбой cURL с кодом выхода, отличным от 0, если код состояния HTTP не 200? Я знаю, что могу использовать -w "%{http_code}" но это помещает его в STDOUT, а не в качестве кода выхода (кроме того, я также заинтересован в захвате вывода, который я не хочу перенаправлять в файл, но на экран).

11 ответов

curl --fail делает часть того, что вы хотите:

от man curl:

-f, --fail

(HTTP) Сбой молча (вообще не выводится) при ошибках сервера. В основном это делается для того, чтобы лучше включать скрипты и т. Д., Чтобы лучше справляться с неудачными попытками. В обычных случаях, когда HTTP-серверу не удается доставить документ, он возвращает HTML-документ с указанием так (что часто также описывает причину и многое другое). Этот флаг предотвратит вывод curl и вернет ошибку 22.

Этот метод не является отказоустойчивым, и бывают случаи, когда неуспешные коды ответов проскальзывают, особенно когда задействована аутентификация (коды ответов 401 и 407).

Но он блокирует вывод на экран.

Если вы просто хотите отобразить содержимое скрученной страницы, вы можете сделать это:

STATUSCODE=$(curl --silent --output /dev/stderr --write-out "%{http_code}" URL)

if test $STATUSCODE -ne 200; then
    # error handling
fi

При этом содержимое страницы записывается в STDERR при записи кода состояния HTTP в STDOUT, поэтому его можно назначить переменной STATUSCODE.

Использовать. Это вызоветдля выхода с кодом состояния 22, когда код ответа >=400.

Однако обратите внимание, что этот флаг является совершенно новым (по состоянию на 15 февраля 2021 г.) и был добавлен в версии 7.76.0, которая относится к более ранней дате ответа @rampion . Таким образом, он может быть недоступен в вашей системе.

https://curl.se/docs/manpage.html

--fail-с-телом

(HTTP) Возвращает ошибку при ошибках сервера, где код ответа HTTP равен 400 или выше). В обычных случаях, когда HTTP-серверу не удается доставить документ, он возвращает HTML-документ, в котором указано это (который часто также описывает причину и многое другое). Этот флаг по-прежнему позволит Curl выводить и сохранять этот контент, но также будет возвращать ошибку 22.

Это альтернатива -f, --fail, которая приводит к сбою завивки в тех же обстоятельствах, но без сохранения содержимого.

См. также -f, --fail. Добавлено в версии 7.76.0.

-f, --fail

(HTTP) Сбой автоматически (без вывода вообще) при ошибках сервера. В основном это делается для включения сценариев и т. д., чтобы лучше справляться с неудачными попытками. В обычных случаях, когда HTTP-серверу не удается доставить документ, он возвращает HTML-документ, в котором указано это (который часто также описывает причину и многое другое). Этот флаг не позволит Curl выводить это и возвращать ошибку 22.

Этот метод не является отказоустойчивым, и бывают случаи, когда неуспешные коды ответа могут проскользнуть, особенно когда используется аутентификация (коды ответа 401 и 407).

См. также --fail-with-body.

Я смог сделать это, используя комбинацию флагов:

curl --silent --show-error --fail URL

- молчит скрывает прогресс и ошибку
--show-error показывает сообщение об ошибке, скрытое --silent
--fail возвращает код выхода> 0, когда запрос не выполняется

Большинство ответов, предоставленных до сих пор, не будут печатать тело ответа HTTP в случае сбоя HTTP-запроса.

Если вы также хотите напечатать тело ответа, даже если код выхода не равен нулю из-за сбоя HTTP-запроса: при условии, что у вас есть Curl v7.76 или новее, просто используйте curl --fail-with-body.

Для более старых версий Curl попробуйте следующее:

      curlf() {
  OUTPUT_FILE=$(mktemp)
  HTTP_CODE=$(curl --silent --output $OUTPUT_FILE --write-out "%{http_code}" "$@")
  if [[ ${HTTP_CODE} -lt 200 || ${HTTP_CODE} -gt 299 ]] ; then
    >&2 cat $OUTPUT_FILE
    return 22
  fi
  cat $OUTPUT_FILE
  rm $OUTPUT_FILE
}

Я закончил с этим на основе ответа Денниса, быстрого однострочного кода, который не работает для кодов состояния, отличных от 200, при сохранении вывода (для stderr):

[ $(curl ... -o /dev/stderr -w "%{http_code}") -eq 200 ]

Да, есть способ сделать это, но он далеко не очевиден, так как включает в себя 3 варианта скручивания:

curl -s --fail --show-error https://httpbin.org/status/200 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/401 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/404 > /dev/null
curl -s --fail --show-error https://bleah-some-wrong-host > /dev/null

Это гарантирует, что success (0) происходит только тогда, когда curl завершает нас с final 2xx код возврата и stdout получает тело и что любые ошибки будут отображаться в stderr.

Обратите внимание, что документация curl может вас немного смущать, поскольку в ней упоминается, что --fail может успешно завершиться для некоторых кодов 401. Основано на тестах, которые не соответствуют действительности, по крайней мере, при использовании с --show-error одновременно.

До сих пор я не смог найти ни одного случая, когда curl вернет успех, когда он не был http-success с этими опциями.

Недавно мне тоже понадобилось что-то подобное, но я также хотел всегда распечатывать результат. Для этого я использовал извлечение http_code и grep.

  out=$(curl -H"Content-Type: application/json"  -w '\nstatus_code=%{http_code}\n' -s http://localhost:4040${uri} -d "${body}")
  code=$(echo ${out}|grep status_code|awk -F"=" '{print $2}')
  echo ${out}
  if [[ ${code} -ge 400 ]];
  then
    exit 2;
  fi;

Это основано на решении @Dennis, но показывает вывод только при ошибке (код возврата не 200):

#!/bin/bash

# Create temp file
SCRATCH=$( mktemp -t tmp.XXXXXXXXXX )
# Cleanup temp file on script exit
function cleanup_on_exit {
    rm -f "$SCRATCH"
}
trap cleanup_on_exit EXIT

# Perform curl call
HTTP_CODE=$( curl -s -o "$SCRATCH" -w '%{http_code}' your..stuff..here )

# Analyze HTTP return code
if [[ ${HTTP_CODE} -ne 200 ]] ; then
    cat "${SCRATCH}"
    exit 1
fi

Альтернативная обработка кода возврата HTTP, где 2XX в порядке:

# Analyze HTTP return code
if [[ ${HTTP_CODE} -lt 200 || ${HTTP_CODE} -gt 299 ]] ; then
    cat "${SCRATCH}"
    exit 1
fi

Вот мое решение - оно используетjqи предполагает, что тело — это json

      #  this code adds a statusCode field to the json it receives and then jq squeezes them together
# curl 7.76.0 will have curl --fail-with-body and thus eliminate all this
  local result
  result=$(
    curl -sL -w ' { "statusCode": %{http_code}} ' -X POST "${headers[@]}" "${endpoint}" \
      -d "${body}"  "$curl_opts" | jq -ren '[inputs] | add'
  )
#   always output the result
  echo "${result}"
#  jq -e will produce an error code if the expression result is false or null - thus resulting in a
# error return code from this function naturally. This is much preferred rather than assume/hardcode
# the existence of a error object in the body payload
  echo "${result}" | jq -re '.statusCode >= 200 and .statusCode < 300' > /dev/null

Недавно я пытался использовать показанные здесь подходы, но постоянно получал ошибку, потому что Curl предоставлял код ответа, как и должно быть.401(curl 7.64.1 (x86_64-apple-darwin19.0). Bash преобразует000401к257поэтому пытаюсь проверить>=200и<=299не был надежным.

В итоге я получаю эту функцию:

      function curl_custom() {
    local RESPONSE_CODE
    RESPONSE_CODE=$(curl -v --silent --output /dev/stderr --write-out "%{response_code}" "$@")

    # Remove leading zeros (if any) to prevent bash interpreting result as octal
    RESPONSE_CODE=${RESPONSE_CODE##+(0)}

    if (( RESPONSE_CODE >= 200 )) && (( RESPONSE_CODE <= 299 )) ; then
        echo "INFO - Got response ${RESPONSE_CODE}"
    else
        echo "ERROR - Request failed with ${RESPONSE_CODE}"
        return 127
    fi
}

Примеры использования:

      curl_custom example.com example.com
curl_custom -X PUT -U user:pass file.json example.com/api

Надеюсь, поможет.

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