วิธีการประเมินรหัสตอบสนอง http จาก bash / shell script?


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
ดี - ขอบคุณ: ฉันได้พบแล้ว - เขียนออก แต่พลาด - เอาท์พุท / dev / null เมื่อเนื้อหาทั้งหมดมาพร้อมกับมัน, รหัสการตอบสนองที่ได้รับหายไปในข้อมูลที่มากเกินไปดังนั้นฉันก็ไม่เห็นมัน ...
โอลาฟ Kock

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

ฉันต้องสาธิตบางสิ่งอย่างรวดเร็วในวันนี้ คิดว่าฉันจะวางไว้ที่นี่ถ้ามีคนต้องการบางสิ่งที่คล้ายกับคำขอของ 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 ดังนั้นจึงเป็นเรื่องที่โง่และโลภมาก เพื่อปรับปรุงสิ่งนี้ฉันจะดูวนลูปผ่านรหัสสถานะต่าง ๆ และทำการกระทำที่แตกต่างกันขึ้นอยู่กับผลลัพธ์


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 เพื่อแยกรหัสผลลัพธ์ออกมา
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}'ทำสิ่งเดียวกันในกระบวนการเดียวอันบริสุทธิ์บริสุทธิ์
tripleee

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ว่ามีเพียงส่วนหัวของการตอบสนองต่อการร้องขอและหลีกเลี่ยงการใช้ไอเอฟเอเป็นข้อเสนอแนะที่นี่ มันแสดงข้อความตีกลับเมื่อพบการตอบสนอง> = 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

นี่คือการดำเนินการของฉันซึ่งเป็น verbose มากกว่าคำตอบก่อนหน้านี้บางส่วน

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} - เงียบ - เอาท์พุท - ชื่อเซิร์ฟเวอร์) - บรรทัดสุดท้ายในผลลัพธ์จะเป็นรหัสตอบกลับ

จากนั้นคุณสามารถแยกรหัสการตอบสนองจากการตอบสนองโดยใช้สิ่งต่อไปนี้โดยที่ X สามารถแสดงว่า regex เพื่อทำเครื่องหมายจุดสิ้นสุดของการตอบกลับ (โดยใช้ตัวอย่าง json ที่นี่)

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

ดูการกำจัดซับสตริง: http://tldp.org/LDP/abs/html/string-manipulation.html


ทำไมคุณถึงใส่รูปแบบในตัวแปรและทำไมคุณถึงใช้สิ่งที่ไร้ประโยชน์echoเพื่อให้ได้ค่าสุดท้าย? เพียงแค่code=${response##*\}}จะง่ายและหลีกเลี่ยงจำนวนของข้อผิดพลาดที่พบบ่อย นอกจากนี้นั่นเป็นรูปแบบ glob ไม่ใช่การแสดงออกปกติที่เหมาะสม
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.