0

curl批量检测网站状态码并邮件告警脚本:3个实战方案让网站故障秒级通知到邮箱

2026.06.14 | youres | 8次围观

为什么要用curl批量检测网站状态码

做运维的都知道,网站挂了你不知道,比网站挂了本身更可怕。老板先于你发现网站打不开,那种尴尬谁经历谁懂。与其等用户投诉,不如自己写个脚本盯着——用curl批量检测网站HTTP状态码,一旦异常自动发邮件告警,这是最朴素也最有效的监控方案。

curl几乎每台Linux服务器都有,不需要装额外依赖;邮件告警不依赖第三方平台,不存在API限额问题。整套方案零成本、轻量级、部署快,适合中小规模网站监控。

方案一:基础串行检测+sendEmail告警

核心思路

从URL列表文件逐行读取网站地址,用curl获取HTTP状态码,连续失败3次则触发邮件告警。串行执行逻辑简单,适合监控10个以内的网站。

脚本代码

#!/bin/bash
# curl批量检测网站状态码+邮件告警
# 适合监控少量网站,串行检测

URL_FILE="/opt/urls.txt"
ADMIN_EMAIL="admin@example.com"
FAIL_THRESHOLD=3
LOG_FILE="/var/log/web_monitor.log"

check_url() {
    local url=$1
    local fail_count=0

    for ((i=1; i<=FAIL_THRESHOLD; i++)); do
        http_code=$(curl -o /dev/null --connect-timeout 5 -s -w "%{http_code}" "$url")
        if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S') $url OK ($http_code)" >> "$LOG_FILE"
            return 0
        fi
        fail_count=$i
        sleep 2
    done

    echo "$(date '+%Y-%m-%d %H:%M:%S') $url FAIL (code=$http_code, retry=$fail_count)" >> "$LOG_FILE"
    send_alert "$url" "$http_code"
}

send_alert() {
    local url=$1
    local code=$2
    local subject="[告警] 网站异常: $url"
    local body="检测时间: $(date '+%Y-%m-%d %H:%M:%S')\n网站地址: $url\nHTTP状态码: $code\n连续失败次数: $FAIL_THRESHOLD\n请尽快排查处理。"

    echo -e "$body" | mail -s "$subject" "$ADMIN_EMAIL"
}

# 主循环
while read -r url; do
    [ -z "$url" ] && continue
    check_url "$url"
done < "$URL_FILE"

URL列表文件格式

https://www.example.com
https://api.example.com
https://shop.example.com

部署要点

  • 确保系统已安装mailx或postfix,否则mail命令无法发送
  • curl的--connect-timeout设5秒足够,太长会拖慢整体检测速度
  • 2xx和3xx状态码都算正常,4xx和5xx才触发告警

方案二:并行检测+xargs加速

为什么需要并行

串行检测50个网站,每个超时5秒,最坏情况耗时250秒——快5分钟了。用xargs并行检测,50个网站10秒内出结果,效率提升20倍以上。

脚本代码

#!/bin/bash
# curl并行批量检测+邮件告警
# 适合监控大量网站

URL_FILE="/opt/urls.txt"
ADMIN_EMAIL="admin@example.com"
PARALLEL=10
LOG_FILE="/var/log/web_monitor.log"
ALERT_FILE="/tmp/web_alert_$(date +%s).txt"

check_single() {
    local url=$1
    local fail=0

    for ((i=1; i<=3; i++)); do
        http_code=$(curl -o /dev/null --connect-timeout 5 -s -w "%{http_code}" "$url")
        if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S') $url OK ($http_code)" >> "$LOG_FILE"
            return 0
        fi
        fail=$i
        sleep 1
    done

    echo "$(date '+%Y-%m-%d %H:%M:%S') $url FAIL (code=$http_code)" >> "$LOG_FILE"
    echo "网站: $url | 状态码: $http_code | 时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$ALERT_FILE"
}

export -f check_single
export LOG_FILE ALERT_FILE

# 并行检测
cat "$URL_FILE" | grep -v '^$' | xargs -P $PARALLEL -I {} bash -c 'check_single "$@"' _ {}

# 批量发送告警邮件
if [ -f "$ALERT_FILE" ] && [ -s "$ALERT_FILE" ]; then
    alert_count=$(wc -l < "$ALERT_FILE")
    subject="[告警] ${alert_count}个网站检测异常"
    {
        echo "以下网站检测异常,请尽快处理:"
        echo "================================"
        cat "$ALERT_FILE"
        echo "================================"
        echo "检测时间: $(date '+%Y-%m-%d %H:%M:%S')"
    } | mail -s "$subject" "$ADMIN_EMAIL"

    rm -f "$ALERT_FILE"
fi

并行数选择建议

  • 10个以内网站:串行即可,PARALLEL=1
  • 10-50个网站:PARALLEL=10
  • 50-200个网站:PARALLEL=20
  • 200个以上:考虑分批检测或用专业监控工具

方案三:crontab定时巡检+HTML格式邮件

核心思路

把检测脚本挂到crontab,每5分钟跑一次。邮件内容用HTML格式排版,包含正常和异常网站的完整状态表,一目了然。

脚本代码

#!/bin/bash
# 定时巡检+HTML格式邮件报告
# crontab: */5 * * * * /opt/web_monitor.sh

URL_FILE="/opt/urls.txt"
ADMIN_EMAIL="admin@example.com"
LOG_DIR="/var/log/web_monitor"
REPORT_FILE="$LOG_DIR/report_$(date +%Y%m%d_%H%M%S).html"
ALERT_ONLY=false  # 设为true则只在异常时发邮件

mkdir -p "$LOG_DIR"

# 生成HTML报告头
cat > "$REPORT_FILE" << 'HEADER'
<!DOCTYPE html>
<html><head><meta charset="UTF-8">
<style>
body{font-family:Arial,sans-serif;margin:20px}
h2{color:#333;border-bottom:2px solid #4CAF50;padding-bottom:8px}
table{border-collapse:collapse;width:100%;margin-top:15px}
th{background:#4CAF50;color:white;padding:10px;text-align:left}
td{padding:8px 10px;border-bottom:1px solid #ddd}
.ok{color:#2e7d32;font-weight:bold}
.fail{color:#c62828;font-weight:bold}
.timestamp{color:#666;font-size:12px}
</style></head><body>
HEADER

echo "<h2>网站状态巡检报告</h2>" >> "$REPORT_FILE"
echo "<p class='timestamp'>检测时间: $(date '+%Y-%m-%d %H:%M:%S')</p>" >> "$REPORT_FILE"
echo "<table><tr><th>网站地址</th><th>状态码</th><th>状态</th><th>耗时</th></tr>" >> "$REPORT_FILE"

alert_list=""

while read -r url; do
    [ -z "$url" ] && continue

    start_time=$(date +%s%N)
    http_code=$(curl -o /dev/null --connect-timeout 5 -s -w "%{http_code}" "$url")
    end_time=$(date +%s%N)
    elapsed=$(( (end_time - start_time) / 1000000 ))

    if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then
        status_class="ok"
        status_text="正常"
    else
        status_class="fail"
        status_text="异常"
        alert_list="${alert_list}${url} (HTTP ${http_code})\n"
    fi

    echo "<tr><td>${url}</td><td>${http_code}</td><td class='${status_class}'>${status_text}</td><td>${elapsed}ms</td></tr>" >> "$REPORT_FILE"
done < "$URL_FILE"

echo "</table></body></html>" >> "$REPORT_FILE"

# 判断是否需要发邮件
alert_count=$(echo -e "$alert_list" | grep -c '异常' 2>/dev/null || echo 0)

if [ "$ALERT_ONLY" = true ] && [ "$alert_count" -eq 0 ]; then
    rm -f "$REPORT_FILE"
    exit 0
fi

if [ "$alert_count" -gt 0 ]; then
    subject="[告警] ${alert_count}个网站异常 - $(date '+%m-%d %H:%M')"
else
    subject="[巡检] 全部网站正常 - $(date '+%m-%d %H:%M')"
fi

cat "$REPORT_FILE" | mail -s "$(echo '$subject' | iconv -t UTF-8)" \
    -a "Content-Type: text/html; charset=UTF-8" "$ADMIN_EMAIL"

crontab配置

# 每5分钟检测一次
*/5 * * * * /opt/web_monitor.sh

# 每30分钟检测一次(非高峰期降低频率)
*/30 0-7 * * * /opt/web_monitor.sh

# 工作时间每5分钟,非工作时间每30分钟
*/5 8-23 * * 1-5 /opt/web_monitor.sh
*/30 0-7 * * * /opt/web_monitor.sh

3个方案对比总结

特性方案一:串行方案二:并行方案三:定时+HTML
适合网站数量10个以内50个以内任意
检测速度
邮件格式纯文本纯文本HTML表格
定时运行需配合crontab需配合crontab内置
部署复杂度
告警策略逐个发邮件合并发邮件按需发邮件

常见问题排查

mail命令发不出邮件

最常见的原因是系统没装邮件发送服务。CentOS装mailxpostfix,Ubuntu装mailutils。装完后用echo "test" | mail -s "test" your@email.com测试一下。

curl状态码为000

000不是HTTP状态码,而是curl自己返回的,表示连接超时或DNS解析失败。检查网络连通性和DNS配置,curl -v能看详细错误信息。

告警邮件太多导致疲劳

加入防抖机制:同一网站5分钟内只告警一次。可以用临时文件记录上次告警时间,脚本开头检查是否在冷却期内。

相关文章

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论