【问题标题】:How to evaluate http response codes from bash/shell script?如何评估来自 bash/shell 脚本的 http 响应代码?
【发布时间】:2011-01-14 06:52:23
【问题描述】:

我感觉我错过了明显的东西,但没有成功使用man [curl|wget] 或谷歌(“http”是一个糟糕的搜索词)。我正在为我们的一个经常失败的网络服务器寻找一个快速而肮脏的修复程序,返回状态代码 500 和错误消息。一旦发生这种情况,就需要重新启动。

由于似乎很难找到根本原因,我们的目标是快速修复,希望它足以弥补我们真正修复它之前的时间(该服务不需要高可用性)

建议的解决方案是创建一个每 5 分钟运行一次的 cron 作业,检查 http://localhost:8080/。如果返回状态码 500,则网络服务器将重新启动。服务器将在一分钟内重新启动,因此无需检查是否已重新启动。

有问题的服务器是 ubuntu 8.04 最小安装,安装了足够的软件包来运行它当前需要的。在 bash 中完成这项任务没有硬性要求,但我希望它能够在这样一个最小的环境中运行,而无需安装任何更多的解释器。

(我对脚本非常熟悉,将 http 状态代码分配给环境变量的命令/选项就足够了 - 这是我一直在寻找但找不到的。)

【问题讨论】:

    标签: http bash shell http-headers


    【解决方案1】:
    1. 假设您已经为您的应用程序实现了一个停止和启动脚本。创建如下脚本,检查应用程序 url 的 http 状态并在 502 的情况下重新启动:

    httpStatusCode=$(curl -s -o /dev/null -w "%{http_code}" https://{your_url}/) 如果 [ $httpStatusCode = 502 ];然后 sh /{path_to_folder}/stopscript.sh sh /{path_to_folder}/startscript.sh fi

    1. 实施一个 cron 作业以每 5 分钟调用一次此脚本。假设上面的脚本名称为 checkBootAndRestart.sh。然后你的 crontab 应该看起来像-*/5 * * * * /{path_to_folder}/checkBootAndRestart.sh

    【讨论】:

      【解决方案2】:

      我没有在 500 代码上对此进行测试,但它适用于其他代码,例如 200、302 和 404。

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

      注意,为 --write-out 提供的格式应该被引用。 正如@ibai 所建议的,添加--head 以发出仅 HEAD 请求。由于页面内容不会被传输,这将在检索成功时节省时间。

      【讨论】:

      • 很好 - 谢谢:我已经找到了 --write-out,但错过了 --output /dev/null。当所有的内容都自带的时候,响应码会迷失在太多的信息中,所以我根本没看到……
      • 我可以将响应代码和输出存储在单独的变量中吗?我想在响应码不是 200 时回显输出
      • @VaibhavBajpai:试试这个:response=$(curl --write-out \\n%{http_code} --silent --output - servername) - 结果中的最后一行将是响应代码。
      • 如果第一个请求的结果是 3XX,这不会显示最终的请求状态。例如,如果返回值为 301 重定向,则此脚本将停在那里。如果添加-IL,则可以获得最终状态。如果要显示所有请求的所有 HTTP 状态,请使用下面的示例。
      • 工作得很好,谢谢!但是在我的情况下(https)我也需要输入--insecure
      【解决方案3】:

      这是我的实现,比之前的一些答案要冗长一些

      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
      

      【讨论】:

      • 这个实现真的有效!!!您将 httpResponseCode 与返回的内容分开!
      【解决方案4】:

      我不喜欢这里将数据与状态混合的答案。 发现这个: 您添加 -f 标志以使 curl 失败并从标准状态变量中获取错误状态代码:$?

      https://unix.stackexchange.com/questions/204762/return-code-for-curl-used-in-a-command-substitution

      我不知道它是否适合这里的每个场景,但它似乎符合我的需求,而且我认为它更容易使用

      【讨论】:

      • -f 和 $?仅在发生错误时为您提供不等于 0 的退出状态,而不是 http 状态
      【解决方案5】:

      虽然accepted response 是一个很好的答案,但它忽略了失败场景。 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
      

      【讨论】:

        【解决方案6】:

        另一种变化:

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

        【讨论】:

          【解决方案7】:

          我今天需要快速演示一些东西并想出了这个。如果有人需要类似于 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
          

          这将在从 200 开始的每个状态更改时发送电子邮件警报,因此它是愚蠢的并且可能是贪婪的。为了改善这一点,我会考虑循环几个状态代码并根据结果执行不同的操作。

          【讨论】:

            【解决方案8】:

            这里是冗长但易于理解的脚本,其灵感来自nicerobot 的解决方案,它只请求响应标头并避免按照here 的建议使用 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"
            

            【讨论】:

              【解决方案9】:

              要添加到上面的@DennisWilliamson 评论:

              @VaibhavBajpai:试试这个:response=$(curl --write-out \n%{http_code} --silent --output - servername) - 结果中的最后一行将是响应代码

              然后,您可以使用以下内容从响应中解析响应代码,其中 X 可以表示正则表达式以标记响应的结束(此处使用 json 示例)

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

              查看子字符串删除:http://tldp.org/LDP/abs/html/string-manipulation.html

              【讨论】:

              • 为什么要将模式放在变量中,为什么要使用useless echo 来获取最终值?只是code=${response##*\}} 更简单,并且避免了许多常见的陷阱。此外,这是一个 glob 模式,而不是正确的正则表达式。
              【解决方案10】:

              这有助于评估 http 状态

              var=`curl -I http://www.example.org 2>/dev/null | head -n 1 | awk -F" " '{print $2}'`
              echo http:$var
              

              【讨论】:

              • head -n 1 | awk '{stuff}' 有点反模式,awk 'NR==1 {stuff}' 在一个进程中做同样的事情,纯 Awk。
              【解决方案11】:

              遵循 3XX 重定向并打印所有请求的响应代码:

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

              【讨论】:

              • grep 将捕获其中包含“HTTP”的所有行。也许grep -m 1 HTTP 只抓取第一个匹配项,如果这是意图,或者可能改为管道到 Awk 以仅解析结果代码。
              【解决方案12】:
              curl --write-out "%{http_code}\n" --silent --output /dev/null "$URL"
              

              有效。如果没有,您必须按回车键才能查看代码本身。

              【讨论】:

                【解决方案13】:

                使用 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
                

                【讨论】:

                • netcat 在这个 HTTPS 几乎无处不在的时代几乎毫无用处。请改用openssl s_client
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-01-10
                • 1970-01-01
                • 1970-01-01
                • 2014-10-21
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多