Как оценить коды ответов http из скрипта bash / shell?

203

У меня такое ощущение, что мне не хватает очевидного, но я не справился с этим man [curl|wget]или Google («http» делает такой плохой поисковый термин). Я ищу быстрое и грязное исправление для одного из наших веб-серверов, которое часто выходит из строя и возвращает код состояния 500 с сообщением об ошибке. Как только это произойдет, его нужно перезапустить.

Поскольку коренную причину, по-видимому, трудно найти, мы стремимся к быстрому исправлению, надеясь, что этого будет достаточно, чтобы преодолеть время, пока мы действительно не сможем это исправить (службе не нужна высокая доступность)

Предлагаемое решение заключается в создании задания cron, которое запускается каждые 5 минут, проверяя http: // localhost: 8080 / . Если это возвращается с кодом состояния 500, веб-сервер будет перезапущен. Сервер будет перезагружен через минуту, поэтому нет необходимости проверять перезапуски, которые уже запущены.

Рассматриваемый сервер представляет собой минимальную установку Ubuntu 8.04 с достаточным количеством установленных пакетов для запуска того, что ему нужно в данный момент. Для выполнения задачи в bash нет строгих требований, но я бы хотел, чтобы она работала в такой минимальной среде без установки дополнительных переводчиков.

(Я достаточно знаком со сценариями, что команды / опции для назначения кода состояния http переменной среды было бы достаточно - это то, что я искал и не мог найти.)

Олаф Кок
источник

Ответы:

316

Я не проверял это на коде 500, но он работает на других, таких как 200, 302 и 404.

response=$(curl --write-out '%{http_code}' --silent --output /dev/null servername)

Обратите внимание, формат, предоставленный для --write-out, должен быть в кавычках. В соответствии с предложением @ibai добавьте --headзапрос только для HEAD. Это сэкономит время при успешном извлечении, поскольку содержимое страницы не будет передано.

Приостановлено до дальнейшего уведомления.
источник
1
Хорошо - спасибо: я уже нашел --write-out, но пропустил --output / dev / null. Когда весь контент идет с ним, код ответа теряется в слишком большом количестве информации, поэтому я просто не видел его ...
Олаф Кок
4
Могу ли я хранить код ответа и вывод в отдельных переменных? Я хотел бы повторить вывод, когда код ответа не 200
Vaibhav Bajpai
7
@VaibhavBajpai: Попробуйте это: response=$(curl --write-out \\n%{http_code} --silent --output - servername)- последняя строка в результате будет код ответа.
Приостановлено до дальнейшего уведомления.
2
Это не показывает окончательный статус запроса, если результатом первого запроса является 3XX. Например, если возвращаемое значение является перенаправлением 301, то этот сценарий просто останавливается на этом. Если вы добавите -IL, то вы можете получить окончательный статус. Если вы хотите показать все HTTP-статусы для всех запросов, используйте мой пример ниже.
silicrockstar
Работает отлично, спасибо! Однако в моем случае (https) мне нужно было также поставить --insecure.
Томаш Рация
42
curl --write-out "%{http_code}\n" --silent --output /dev/null "$URL"

работает. Если нет, вы должны нажать кнопку возврата, чтобы просмотреть сам код.

hd1
источник
33

Мне нужно было что-то быстро показать сегодня и придумал это. Думаю, я бы разместил это здесь, если бы кому-то нужно что-то похожее на запрос ОП.

#!/bin/bash

status_code=$(curl --write-out %{http_code} --silent --output /dev/null www.bbc.co.uk/news)

if [[ "$status_code" -ne 200 ]] ; then
  echo "Site status changed to $status_code" | mail -s "SITE STATUS CHECKER" "my_email@email.com" -r "STATUS_CHECKER"
else
  exit 0
fi

Это будет отправлять уведомление по электронной почте при каждом изменении состояния от 200, так что это глупо и потенциально жадно. Чтобы улучшить это, я бы посмотрел на циклический просмотр нескольких кодов состояния и выполнение различных действий в зависимости от результата.

Крис Гиллатт
источник
20

Хотя принятый ответ является хорошим ответом, он не учитывает сценарии сбоев. curlвернется, 000если в запросе произошла ошибка или произошел сбой соединения.

url='http://localhost:8080/'
status=$(curl --head --location --connect-timeout 5 --write-out %{http_code} --silent --output /dev/null ${url})
[[ $status == 500 ]] || [[ $status == 000 ]] && echo restarting ${url} # do start/restart logic

Примечание: это выходит за рамки запрошенной 500проверки статуса, чтобы также подтвердить, что curlможно даже подключиться к серверу (то есть возвратить 000).

Создайте функцию из нее:

failureCode() {
    local url=${1:-http://localhost:8080}
    local code=${2:-500}
    local status=$(curl --head --location --connect-timeout 5 --write-out %{http_code} --silent --output /dev/null ${url})
    [[ $status == ${code} ]] || [[ $status == 000 ]]
}

Тест получения 500:

failureCode http://httpbin.org/status/500 && echo need to restart

Проверка получения ошибки / сбоя соединения (т.е. 000):

failureCode http://localhost:77777 && echo need to start

Тест не получен 500:

failureCode http://httpbin.org/status/400 || echo not a failure
nicerobot
источник
9

С помощью netcat и awk вы можете обработать ответ сервера вручную:

if netcat 127.0.0.1 8080 <<EOF | awk 'NR==1{if ($2 == "500") exit 0; exit 1;}'; then
GET / HTTP/1.1
Host: www.example.com

EOF

    apache2ctl restart;
fi
марко
источник
9

Чтобы выполнить перенаправления 3XX и распечатать коды ответов для всех запросов:

HTTP_STATUS="$(curl -IL --silent example.com | grep HTTP )";    
echo "${HTTP_STATUS}";
siliconrockstar
источник
grepБудет захватывать все строки с «HTTP» в них. Может быть, grep -m 1 HTTPтолько для получения первого совпадения, если это является намерением, или, может быть, вместо того, чтобы передать Awk, чтобы проанализировать только код результата.
tripleee
3

это может помочь оценить статус http

var=`curl -I http://www.example.org 2>/dev/null | head -n 1 | awk -F" " '{print $2}'`
echo http:$var
Танго
источник
2
head -n 1 | awk '{stuff}' немного антипаттерн, awk 'NR==1 {stuff}'делает то же самое в одном процессе, чистый Awk.
тройной
3

Еще один вариант:

       status=$(curl -sS  -I https://www.healthdata.gov/user/login  2> /dev/null | head -n 1 | cut -d' ' -f2)
status_w_desc=$(curl -sS  -I https://www.healthdata.gov/user/login  2> /dev/null | head -n 1 | cut -d' ' -f2-)
dkinzer
источник
2

Здесь идет скучный - но простой для понимания - скрипт, навеянный решением nicerobot , который запрашивает только заголовки ответа и избегает использования IFS, как предлагается здесь . Он выводит сообщение о сбое, когда встречает ответ> = 400. Этот эхо может быть заменен скриптом отказов.

# set the url to probe
url='http://localhost:8080'
# use curl to request headers (return sensitive default on timeout: "timeout 500"). Parse the result into an array (avoid settings IFS, instead use read)
read -ra result <<< $(curl -Is --connect-timeout 5 "${url}" || echo "timeout 500")
# status code is second element of array "result"
status=${result[1]}
# if status code is greater than or equal to 400, then output a bounce message (replace this with any bounce script you like)
[ $status -ge 400  ] && echo "bounce at $url with status $status"
Томас Праксл
источник
1

мне не понравились ответы, которые смешивают данные со статусом. нашел это: вы добавили флаг -f для сбоя curl и забрали код состояния ошибки из стандартного состояния var: $?

/unix/204762/return-code-for-curl-used-in-a-command-substitution

я не знаю, подходит ли он для каждого сценария здесь, но, кажется, он соответствует моим потребностям, и я думаю, что с ним намного легче работать

Натан Г
источник
1

Вот моя реализация, которая немного более многословна, чем некоторые из предыдущих ответов

curl https://somewhere.com/somepath   \
--silent \
--insecure \
--request POST \
--header "your-curl-may-want-a-header" \
--data @my.input.file \
--output site.output \
--write-out %{http_code} \
  > http.response.code 2> error.messages
errorLevel=$?
httpResponse=$(cat http.response.code)


jq --raw-output 'keys | @csv' site.output | sed 's/"//g' > return.keys
hasErrors=`grep --quiet --invert errors return.keys;echo $?`

if [[ $errorLevel -gt 0 ]] || [[ $hasErrors -gt 0 ]] || [[ "$httpResponse" != "200" ]]; then
  echo -e "Error POSTing https://somewhere.com/somepath with input my.input (errorLevel $errorLevel, http response code $httpResponse)" >> error.messages
  send_exit_message # external function to send error.messages to whoever.
fi
AG6HQ
источник
0

Чтобы добавить комментарий @DennisWilliamson выше:

@VaibhavBajpai: Попробуйте это: response = $ (curl --write-out \ n% {http_code} --silent --output - имя_сервера) - последняя строка в результате будет кодом ответа

Затем вы можете проанализировать код ответа из ответа, используя что-то вроде следующего, где X может означать регулярное выражение, чтобы отметить конец ответа (используя пример json здесь)

X='*\}'
code=$(echo ${response##$X})

См. Удаление подстроки: http://tldp.org/LDP/abs/html/string-manipulation.html.

user1015492
источник
Зачем вам помещать шаблон в переменную, и зачем использовать бесполезныйecho для получения окончательного значения? Просто code=${response##*\}}это проще и позволяет избежать ряда распространенных ошибок. Кроме того, это шаблон глобуса, а не правильное регулярное выражение.
tripleee