¿Cómo evaluar los códigos de respuesta http del script bash / shell?


203

Tengo la sensación de que me falta lo obvio, pero no he tenido éxito con man [curl|wget]o google ("http" hace un término de búsqueda tan malo). Estoy buscando una solución rápida y sucia para uno de nuestros servidores web que falla con frecuencia, devolviendo el código de estado 500 con un mensaje de error. Una vez que esto sucede, debe reiniciarse.

Como la causa raíz parece ser difícil de encontrar, buscamos una solución rápida, con la esperanza de que sea suficiente para cerrar el tiempo hasta que realmente podamos solucionarlo (el servicio no necesita alta disponibilidad)

La solución propuesta es crear un trabajo cron que se ejecute cada 5 minutos, verificando http: // localhost: 8080 / . Si esto vuelve con el código de estado 500, el servidor web se reiniciará. El servidor se reiniciará en menos de un minuto, por lo que no hay necesidad de verificar si los reinicios ya se están ejecutando.

El servidor en cuestión es una instalación mínima de ubuntu 8.04 con suficientes paquetes instalados para ejecutar lo que necesita actualmente. No hay un requisito difícil para hacer la tarea en bash, pero me gustaría que se ejecute en un entorno tan mínimo sin instalar más intérpretes.

(Estoy suficientemente familiarizado con los scripts que el comando / opciones para asignar el código de estado http a una variable de entorno sería suficiente; esto es lo que he buscado y no pude encontrar).

Respuestas:


316

No he probado esto en un código 500, pero funciona en otros como 200, 302 y 404.

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

Tenga en cuenta que se debe citar el formato proporcionado para --write-out. Según lo sugerido por @ibai, agregue --headpara hacer una solicitud HEAD only. Esto ahorrará tiempo cuando la recuperación sea exitosa ya que el contenido de la página no se transmitirá.


1
Agradable, gracias: ya he encontrado --write-out, pero perdí el --output / dev / null Cuando todo el contenido viene con él, el código de respuesta se pierde en demasiada información, así que simplemente no lo vi ...
Olaf Kock

44
¿Puedo almacenar tanto el código de respuesta como la salida en variables separadas? Me gustaría hacer eco de la salida cuando el código de respuesta no es 200
Vaibhav Bajpai

77
@VaibhavBajpai: Pruebe esto: response=$(curl --write-out \\n%{http_code} --silent --output - servername)la última línea en el resultado será el código de respuesta.
Pausado hasta nuevo aviso.

2
Esto no muestra el estado de la solicitud final si el resultado de la primera solicitud es un 3XX. Por ejemplo, si el valor devuelto es una redirección 301, entonces este script simplemente se detiene allí. Si agrega -IL, puede obtener el estado final. Si desea mostrar todos los estados HTTP para todas las solicitudes, use mi ejemplo a continuación.
siliconrockstar el

Funciona muy bien, gracias! Sin embargo, en mi caso (https) también necesitaba poner --insecure.
Tomasz Racia

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

trabajos. Si no, debe presionar regresar para ver el código en sí.


33

Necesitaba demostrar algo rápidamente hoy y se me ocurrió esto. Pensé que lo colocaría aquí si alguien necesitara algo similar a la solicitud del 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

Esto enviará una alerta por correo electrónico sobre cada cambio de estado desde 200, por lo que es tonto y potencialmente codicioso. Para mejorar esto, consideraría recorrer varios códigos de estado y realizar diferentes acciones dependiendo del resultado.


20

Aunque la respuesta aceptada es una buena respuesta, pasa por alto los escenarios de falla. curlregresará 000si hay un error en la solicitud o si hay una falla en la conexión.

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: esto va un poco más allá de la 500verificación de estado solicitada para confirmar que curlincluso puede conectarse al servidor (es decir, regresa 000).

Crea una función a partir de ella:

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

Prueba obteniendo un 500:

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

Prueba obteniendo error / falla de conexión (es decir 000):

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

Prueba no obteniendo un 500:

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

9

Con netcat y awk puede manejar la respuesta del 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 los redireccionamientos 3XX e imprimir códigos de respuesta para todas las solicitudes:

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

El grepcapturará todas las líneas con "http" en ellos. Tal vez grep -m 1 HTTPsolo para agarrar la primera coincidencia, si esa es la intención, o tal vez en lugar de ir a Awk para analizar solo el código de resultado.
tripleee

3

Esto puede ayudar a evaluar el estado de 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}' es un poco antipatrón, awk 'NR==1 {stuff}'hace lo mismo en un proceso, puro Awk.
tripleee

3

Otra variante:

       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

Aquí viene el guión largo, pero fácil de entender, inspirado en la solución de nicerobot , que solo solicita los encabezados de respuesta y evita usar IFS como se sugiere aquí . Emite un mensaje de rebote cuando encuentra una respuesta> = 400. Este eco se puede reemplazar con un script de rebote.

# 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

No me gustaron las respuestas aquí que mezclan los datos con el estado. encontró esto: agrega el indicador -f para que el rizo falle y seleccione el código de estado de error del estado estándar var: $?

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

No sé si es perfecto para cada escenario aquí, pero parece satisfacer mis necesidades y creo que es mucho más fácil trabajar con él.


1

Aquí está mi implementación, que es un poco más detallada que algunas de las respuestas 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 agregar a @DennisWilliamson el comentario anterior:

@VaibhavBajpai: Intente esto: respuesta = $ (curl --write-out \ n% {http_code} --silent --output - servername) - la última línea en el resultado será el código de respuesta

Luego puede analizar el código de respuesta de la respuesta usando algo como lo siguiente, donde X puede significar una expresión regular para marcar el final de la respuesta (usando un ejemplo de json aquí)

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

Consulte Eliminación de subcadenas: http://tldp.org/LDP/abs/html/string-manipulation.html


¿Por qué pondría el patrón en una variable y por qué usaría un inútilecho para obtener el valor final? Just code=${response##*\}}es más simple y evita una serie de dificultades comunes. Además, ese es un patrón global, no una expresión regular adecuada.
tripleee
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.