Могу ли я заставить 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.
Использовать
Однако обратите внимание, что этот флаг является совершенно новым (по состоянию на 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
Надеюсь, поможет.