Làm cách nào để đánh giá mã phản hồi http từ bash / shell script?


203

Tôi có cảm giác rằng tôi đang thiếu điều hiển nhiên, nhưng đã không thành công với man [curl|wget]hoặc google ("http" tạo ra một cụm từ tìm kiếm tồi tệ như vậy). Tôi đang tìm kiếm một bản sửa lỗi nhanh & bẩn cho một trong những máy chủ web của chúng tôi thường xuyên bị lỗi, trả lại mã trạng thái 500 với thông báo lỗi. Một khi điều này xảy ra, nó cần phải được khởi động lại.

Vì nguyên nhân gốc rễ có vẻ khó tìm, chúng tôi đang hướng đến một giải pháp nhanh chóng, hy vọng rằng nó sẽ đủ để thu hẹp thời gian cho đến khi chúng tôi thực sự có thể khắc phục nó (dịch vụ không cần tính sẵn sàng cao)

Giải pháp được đề xuất là tạo một công việc định kỳ chạy cứ sau 5 phút, kiểm tra http: // localhost: 8080 / . Nếu điều này trở lại với mã trạng thái 500, máy chủ web sẽ được khởi động lại. Máy chủ sẽ khởi động lại trong vòng một phút, do đó không cần kiểm tra khởi động lại đã chạy.

Máy chủ được đề cập là một bản cài đặt tối thiểu Ubuntu 8.04 với các gói vừa đủ được cài đặt để chạy những gì nó cần. Không có yêu cầu khó khăn để thực hiện nhiệm vụ trong bash, nhưng tôi muốn nó chạy trong một môi trường tối thiểu như vậy mà không cần cài đặt thêm bất kỳ trình thông dịch nào.

(Tôi đủ quen thuộc với kịch bản lệnh rằng các lệnh / tùy chọn để gán mã trạng thái http cho biến môi trường là đủ - đây là thứ tôi đã tìm và không thể tìm thấy.)

Câu trả lời:


316

Tôi chưa thử nghiệm mã này trên 500 mã, nhưng nó hoạt động trên các mã khác như 200, 302 và 404.

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

Lưu ý, định dạng được cung cấp cho --write-out nên được trích dẫn. Theo đề xuất của @ibai, hãy thêm --headđể thực hiện một yêu cầu CHÍNH. Điều này sẽ tiết kiệm thời gian khi truy xuất thành công vì nội dung trang sẽ không được truyền đi.


1
Rất vui - cảm ơn: Tôi đã tìm thấy - viết ra, nhưng đã bỏ lỡ --output / dev / null. Khi tất cả nội dung đi kèm với nó, mã phản hồi bị mất quá nhiều thông tin, vì vậy tôi chỉ không thấy nó ...
Olaf Kock

4
Tôi có thể lưu trữ cả mã phản hồi và đầu ra trong các biến riêng biệt không? Tôi muốn lặp lại đầu ra khi mã phản hồi không phải là 200
Vaibhav Bajpai

7
@VaibhavBajpai: Hãy thử điều này: response=$(curl --write-out \\n%{http_code} --silent --output - servername)- dòng cuối cùng trong kết quả sẽ là mã phản hồi.
Tạm dừng cho đến khi có thông báo mới.

2
Điều này không hiển thị trạng thái yêu cầu cuối cùng nếu kết quả của yêu cầu đầu tiên là 3XX. Ví dụ: nếu giá trị được trả về là chuyển hướng 301, thì tập lệnh này chỉ dừng ở đó. Nếu bạn thêm -IL, thì bạn có thể nhận trạng thái cuối cùng. Nếu bạn muốn hiển thị tất cả các trạng thái HTTP cho tất cả các yêu cầu, hãy sử dụng ví dụ của tôi dưới đây.
siliconrockstar

Làm việc tuyệt vời, cảm ơn! Tuy nhiên trong trường hợp của tôi (https) tôi cũng cần phải đặt --insecure.
Tomasz Racia

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

làm. Nếu không, bạn phải nhấn return để xem mã.


33

Tôi cần phải demo một cái gì đó nhanh chóng ngày hôm nay và đưa ra điều này. Tôi nghĩ rằng tôi sẽ đặt nó ở đây nếu ai đó cần một cái gì đó tương tự như yêu cầu của 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

Điều này sẽ gửi một cảnh báo email về mỗi thay đổi trạng thái từ 200, vì vậy nó thật ngu ngốc và có khả năng tham lam. Để cải thiện điều này, tôi sẽ xem xét việc lặp qua một số mã trạng thái và thực hiện các hành động khác nhau tùy thuộc vào kết quả.


20

Mặc dù phản hồi được chấp nhận là một câu trả lời tốt, nhưng nó bỏ qua các kịch bản thất bại. curlsẽ trở lại 000nếu có lỗi trong yêu cầu hoặc có lỗi kết nối.

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

Lưu ý: điều này vượt xa một chút 500kiểm tra trạng thái được yêu cầu để cũng xác nhận rằng curlthậm chí có thể kết nối với máy chủ (tức là trả về 000).

Tạo một chức năng từ nó:

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

Kiểm tra nhận được một 500:

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

Kiểm tra lỗi nhận / lỗi kết nối (ví dụ 000):

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

Kiểm tra không nhận được 500:

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

9

Với netcat và awk, bạn có thể xử lý phản hồi của máy chủ theo cách thủ công:

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

Để thực hiện theo chuyển hướng 3XX và in mã phản hồi cho tất cả các yêu cầu:

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

Các grepsẽ nắm bắt tất cả các dòng với "HTTP" trong đó. Có lẽ grep -m 1 HTTPchỉ lấy trận đấu đầu tiên, nếu đó là ý định, hoặc có thể thay vào đó là chuyển sang Awk để phân tích ra mã kết quả.
tripleee

3

điều này có thể giúp đánh giá tình trạng 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}' là một chút của một antipotype, awk 'NR==1 {stuff}'thực hiện điều tương tự trong một quy trình, Awk thuần túy.
tripleee

3

Một biến thể khác:

       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

Ở đây có đoạn mã dài - nhưng dễ hiểu - được lấy cảm hứng từ giải pháp của nicerobot , chỉ yêu cầu các tiêu đề phản hồi và tránh sử dụng IFS như đề xuất ở đây . Nó xuất ra một thông báo thoát khi gặp phản hồi> = 400. Tiếng vang này có thể được thay thế bằng tập lệnh thoát.

# 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

tôi không thích câu trả lời ở đây trộn dữ liệu với trạng thái. tìm thấy điều này: bạn thêm cờ -f để curl không thành công và nhận mã trạng thái lỗi từ trạng thái tiêu chuẩn var: $?

/unix/204762/return-code-for-curl- used-in-a-common-substlation

Tôi không biết nó có hoàn hảo cho mọi kịch bản ở đây không, nhưng nó có vẻ phù hợp với nhu cầu của tôi và tôi nghĩ làm việc với nó dễ dàng hơn nhiều


1

Đây là cách thực hiện của tôi, dài hơn một chút so với một số câu trả lời trước đó

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

Để thêm vào @DennisWilliamson bình luận ở trên:

@VaibhavBajpai: Hãy thử điều này: answer = $ (curl --write-out \ n% {http_code} --silent --output - servername) - dòng cuối cùng trong kết quả sẽ là mã phản hồi

Sau đó, bạn có thể phân tích mã phản hồi từ phản hồi bằng cách sử dụng một cái gì đó như sau, trong đó X có thể biểu thị một biểu thức chính quy để đánh dấu kết thúc của phản hồi (sử dụng ví dụ json ở đây)

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

Xem Xóa chuỗi con: http://tldp.org/LDP/abs/html/opes-manipulation.html


Tại sao bạn lại đặt mô hình vào một biến và tại sao bạn sẽ sử dụng một giá trị vô dụngecho để có được giá trị cuối cùng? Chỉ code=${response##*\}}đơn giản là và tránh một số cạm bẫy phổ biến. Ngoài ra, đó là một mô hình toàn cầu, không phải là một biểu thức chính quy.
tripleee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.