Як оцінити коди відповідей http з скрипту bash / shell?


203

У мене таке відчуття, що я пропускаю очевидне, але не досягли успіху з man [curl|wget]Google або Google ("http" робить такий поганий пошуковий термін). Я шукаю швидке та брудне виправлення до одного з наших веб-серверів, який часто не працює, повертаючи код статусу 500 із повідомленням про помилку. Як тільки це станеться, його потрібно перезапустити.

Оскільки, здається, першопричину важко знайти, ми прагнемо швидкого виправлення, сподіваючись, що цього буде достатньо, щоб зменшити час, поки ми не зможемо це виправити (сервісу не потрібна висока доступність)

Запропоноване рішення полягає у створенні завдання cron, яке працює кожні 5 хвилин, перевіряючи http: // localhost: 8080 / . Якщо це повернеться з кодом статусу 500, веб-сервер буде перезапущений. Сервер перезапуститься за хвилину, тому не потрібно перевіряти наявність уже запущених перезавантажень.

Сервер, про який йдеться, - це мінімальна установка ubuntu 8.04 з достатньою кількістю встановлених пакетів, щоб запустити те, що йому потрібно. Немає жодної жорсткої вимоги виконувати завдання в баші, але я хотів би, щоб вона працювала в такому мінімальному середовищі, не встановлюючи більше перекладачів.

(Я достатньо знайомий з сценаріями, що команд / параметрів для призначення коду статусу http мінливій середовищі буде достатньо - це те, що я шукав і не міг знайти.)

Відповіді:


316

Я не перевіряв це на коді 500, але він працює на таких, як 200, 302 та 404.

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

Зауважте, формат, передбачений для виписування, повинен бути цитований. Як запропонував @ibai, додайте, --headщоб зробити запит лише HEAD. Це заощадить час при успішному пошуку, оскільки вміст сторінки не передаватиметься.


1
Приємно - дякую: я вже знайшов - виписати, але пропустив --output / dev / null. Коли весь вміст поставляється разом із ним, код відповіді втрачається в занадто великій кількості інформації, тому я його просто не бачив ...
Олаф Кок

4
Чи можу я зберігати і код відповіді, і вихід у окремі змінні? Я хотів би повторити висновок, коли код відповіді не 200
Vaibhav Bajpai

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

2
Це не показує остаточний статус запиту, якщо результатом першого запиту є 3XX. Наприклад, якщо повернене значення - це переспрямування 301, цей скрипт просто зупиняється на цьому. Якщо ви додасте -IL, ви можете отримати остаточний статус. Якщо ви хочете показати всі статуси HTTP для всіх запитів, скористайтеся моїм прикладом нижче.
siliconrockstar

Працюю чудово, дякую! Однак у моєму випадку (https) мені потрібно було також поставити --insecure.
Tomasz Racia

42
curl --write-out "%{http_code}\n" --silent --output /dev/null "$URL"

працює. Якщо ні, вам потрібно натиснути return, щоб переглянути сам код.


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

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}";

grepБуде захоплювати все рядки з «HTTP» в них. Можливо, grep -m 1 HTTPлише схопити перший матч, якщо це є наміром, або, замість цього, подати на Awk, щоб розібрати лише результат результату.
трійка

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-)

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, щоб згорнутись з ладу, і забрати код статусу помилки зі стандартної змінної стану: $?

/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

0

Щоб додати до коментаря @DennisWilliamson вище:

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

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

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

Див. Розділ Видалення підрядків: http://tldp.org/LDP/abs/html/string-manipulation.html


Чому б ви поставили шаблон у змінну, і чому б ви використали марнийecho для отримання кінцевого значення? Просто code=${response##*\}}простіше і дозволяє уникнути низки поширених підводних каменів. Крім того, це глобальний зразок, а не правильний регулярний вираз.
трійка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.