Como avaliar os códigos de resposta http do script bash / shell?


203

Tenho a sensação de que estou perdendo o óbvio, mas não consegui man [curl|wget] google ("http" faz um termo de pesquisa tão ruim). Estou procurando uma correção rápida e suja para um de nossos servidores da Web que frequentemente falha, retornando o código de status 500 com uma mensagem de erro. Quando isso acontece, ele precisa ser reiniciado.

Como a causa raiz parece difícil de encontrar, estamos buscando uma solução rápida, esperando que seja suficiente para diminuir o tempo até que possamos corrigi-la (o serviço não precisa de alta disponibilidade)

A solução proposta é criar um trabalho cron que seja executado a cada 5 minutos, verificando http: // localhost: 8080 / . Se isso retornar com o código de status 500, o servidor da web será reiniciado. O servidor será reiniciado em menos de um minuto, portanto, não há necessidade de verificar se há reinicializações em execução.

O servidor em questão é uma instalação mínima do ubuntu 8.04 com apenas pacotes suficientes instalados para executar o que ele precisa atualmente. Não há um requisito difícil de executar a tarefa no bash, mas eu gostaria que ela fosse executada em um ambiente tão mínimo sem instalar mais intérpretes.

(Estou suficientemente familiarizado com scripts que o comando / opções para atribuir o código de status http a uma variável de ambiente seria suficiente - é isso que eu procurei e não consegui encontrar.)

Respostas:


316

Não testei isso em um código 500, mas funciona em outros como 200, 302 e 404.

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

Observe que o formato fornecido para --write-out deve ser citado. Conforme sugerido por @ibai, adicione --headpara fazer uma solicitação somente HEAD. Isso economizará tempo quando a recuperação for bem-sucedida, pois o conteúdo da página não será transmitido.


1
Agradável - obrigado: eu já encontrei --write-out, mas perdi o --output / dev / null. Quando todo o conteúdo vem com ele, o código de resposta se perde no muita informação, então eu simplesmente não vê-lo ...
— Olaf Kock

4
Posso armazenar o código de resposta e a saída em variáveis ​​separadas? Eu gostaria de fazer eco a saída quando o código de resposta não é 200
— Vaibhav Bajpai

7
@VaibhavBajpai: Tente o seguinte: response=$(curl --write-out \\n%{http_code} --silent --output - servername)- a última linha no resultado será o código de resposta.
— Pausado até novo aviso.

2
Isso não mostra o status da solicitação final se o resultado da primeira solicitação for um 3XX. Por exemplo, se o valor retornado for um redirecionamento 301, esse script simplesmente pára por aí. Se você adicionar -IL, poderá obter o status final. Se você deseja mostrar todos os status HTTP para todas as solicitações, use meu exemplo abaixo.
— Siliconrockstar

Trabalhando muito bem, obrigado! No entanto, no meu caso (https) eu precisava colocar --insecuretambém.
— Tomasz Racia 12/09/16

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

trabalho. Caso contrário, você deve pressionar return para visualizar o próprio código.


33

Eu precisava demonstrar algo rapidamente hoje e veio com isso. Pensei em colocá-lo aqui se alguém precisasse de algo semelhante à solicitação do OP.

#!/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

Isso enviará um alerta por e-mail sobre cada alteração de estado de 200, por isso é idiota e potencialmente ganancioso. Para melhorar isso, eu examinaria vários códigos de status e executaria ações diferentes, dependendo do resultado.


20

Embora a resposta aceita seja uma boa resposta, ela ignora os cenários de falha. curlretornará 000se houver um erro na solicitação ou se houver uma falha na conexão.

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

Nota: isso vai um pouco além da 500verificação de status solicitada para confirmar também que curlpode até se conectar ao servidor (ou seja, retorna 000).

Crie uma função a partir dela:

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 ]]
}

Teste para obter um 500:

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

Teste para obter erro / falha na conexão (ou seja 000):

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

Teste não obtendo um 500:

failureCode http://httpbin.org/status/400 || echo not a failure

9

Com o netcat e o awk, você pode manipular a resposta do servidor manualmente:

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

Para seguir os redirecionamentos 3XX e imprimir códigos de resposta para todas as solicitações:

HTTP_STATUS="$(curl -IL --silent example.com | grep HTTP )";    
echo "${HTTP_STATUS}";

O grepirá capturar todas as linhas com "HTTP" nelas. Talvez grep -m 1 HTTPapenas pegue a primeira partida, se essa for a intenção, ou talvez vá até o Awk para analisar apenas o código do resultado.
— tripleee

3

isso pode ajudar a avaliar o status 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}' é um pouco antipadrão, awk 'NR==1 {stuff}'faz a mesma coisa em um processo, o Awk puro.
— tripleee

3

Outra variação:

       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

Aí vem o script longo, mas fácil de entender, inspirado na solução do nicerobot , que apenas solicita os cabeçalhos de resposta e evita o uso do IFS, conforme sugerido aqui . Ele gera uma mensagem de devolução quando encontra uma resposta> = 400. Esse eco pode ser substituído por um script de devolução.

# 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

Não gostei das respostas aqui que misturam os dados com o status. encontrou o seguinte: você adiciona o sinalizador -f para que a ondulação falhe e escolhe o código de status do erro no status padrão var: $?

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

não sei se é perfeito para todos os cenários aqui, mas parece atender às minhas necessidades e acho muito mais fácil trabalhar com


1

Aqui está minha implementação, que é um pouco mais detalhada do que algumas das respostas anteriores

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

Para adicionar ao @DennisWilliamson, o comentário acima:

@VaibhavBajpai: Experimente o seguinte: response = $ (curl --write-out \ n% {http_code} --silent --output - servername) - a última linha do resultado será o código de resposta

Em seguida, você pode analisar o código de resposta da resposta usando algo como o seguinte, em que X pode significar uma regex para marcar o final da resposta (usando um exemplo json aqui)

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

Consulte Remoção de Substring: http://tldp.org/LDP/abs/html/string-manipulation.html


Por que você colocaria o padrão em uma variável e por que usaria um inútilecho para obter o valor final? Just code=${response##*\}}é mais simples e evita uma série de armadilhas comuns. Além disso, esse é um padrão global, não uma expressão regular adequada.
— tripleee
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.