0

Shell脚本curl重定向异常多通道告警:钉钉+企业微信+邮件3路通知让网站问题无处遁形

2026.06.05 | youres | 20次围观

为什么需要多通道告警

单通道告警最大的问题是——消息可能被淹没。钉钉群里几百条消息,你的告警可能3秒就被刷走了;企业微信周末没人看;邮件进了垃圾箱。三路通知同时发,至少有一路能被看到。

重定向异常是网站运维中常见的隐藏问题:跳转次数过多、跳转到了意外域名、UTM参数在跳转中丢失。这些问题不会触发传统的状态码告警(因为HTTP 200也算正常),需要专门检测。

检测逻辑设计

脚本需要检测以下几种重定向异常:

  • 跳转次数超限:num_redirects超过阈值(默认5次)
  • 终点域名异常:最终URL不在白名单内
  • 跳转耗时过长:time_redirect超过阈值(默认2秒)
  • 状态码异常:最终状态码非200

核心检测函数

#!/bin/bash
# curl重定向异常检测核心函数
# 参数:$1=检测URL, $2=最大跳转次数, $3=最大耗时(秒)

check_redirect() {
    local url="$1"
    local max_redirects="${2:-5}"
    local max_time="${3:-2}"
    
    local result
    result=$(curl -sL -o /dev/null -w '%{http_code}|%{num_redirects}|%{url_effective}|%{time_redirect}' \
        --max-redirs 10 --connect-timeout 5 -m 15 "$url" 2>&1)
    
    local http_code=$(echo "$result" | cut -d'|' -f1)
    local num_redirects=$(echo "$result" | cut -d'|' -f2)
    local url_effective=$(echo "$result" | cut -d'|' -f3)
    local time_redirect=$(echo "$result" | cut -d'|' -f4)
    
    local alerts=""
    
    # 检查跳转次数
    if [ "$num_redirects" -gt "$max_redirects" ]; then
        alerts="${alerts}跳转次数超限(${num_redirects}>${max_redirects}); "
    fi
    
    # 检查耗时
    if awk "BEGIN{exit !($time_redirect > $max_time)}"; then
        alerts="${alerts}跳转耗时过长(${time_redirect}s>${max_time}s); "
    fi
    
    # 检查状态码
    if [ "$http_code" != "200" ]; then
        alerts="${alerts}状态码异常(${http_code}); "
    fi
    
    # 检查终点域名
    local effective_domain=$(echo "$url_effective" | awk -F/ '{print $3}')
    if ! echo "$ALLOWED_DOMAINS" | grep -q "$effective_domain"; then
        alerts="${alerts}终点域名异常(${effective_domain}); "
    fi
    
    if [ -n "$alerts" ]; then
        echo "ALERT|$url|$alerts|$url_effective"
        return 1
    else
        echo "OK|$url|$num_redirects次跳转|${time_redirect}s|$url_effective"
        return 0
    fi
}

钉钉告警推送

# 钉钉机器人Webhook推送
# 支持 text 和 markdown 两种格式

send_dingtalk() {
    local message="$1"
    local webhook="https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_TOKEN}"
    
    # 加签安全设置
    local timestamp=$(date +%s%3N)
    local stringToSign="${timestamp}\n${DINGTALK_SECRET}"
    local sign=$(echo -ne "$stringToSign" | openssl dgst -sha256 -hmac "$DINGTALK_SECRET" -binary | base64)
    
    local payload=$(cat <<EOF
{
    "msgtype": "markdown",
    "markdown": {
        "title": "重定向异常告警",
        "text": "## 🚨 重定向异常告警\n\n${message}\n\n> 时间: $(date '+%Y-%m-%d %H:%M:%S')"
    },
    "at": {
        "isAtAll": true
    }
}
EOF
)
    
    curl -s "$webhook×tamp=$timestamp&sign=$sign" \
        -H 'Content-Type: application/json' \
        -d "$payload" > /dev/null
}

企业微信告警推送

# 企业微信机器人Webhook推送

send_wecom() {
    local message="$1"
    local webhook="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${WECOM_KEY}"
    
    local payload=$(cat <<EOF
{
    "msgtype": "markdown",
    "markdown": {
        "content": "## 🚨 重定向异常告警\n\n${message}\n\n> 时间: $(date '+%Y-%m-%d %H:%M:%S')"
    }
}
EOF
)
    
    curl -s "$webhook" \
        -H 'Content-Type: application/json' \
        -d "$payload" > /dev/null
}

邮件告警推送

# 使用sendmail或mail命令发送邮件
# 也可以用curl直接调用SMTP

send_email() {
    local message="$1"
    local subject="[告警] 网站重定向异常 - $(date '+%Y-%m-%d %H:%M')"
    
    # 方式1:使用mail命令
    echo "$message" | mail -s "$subject" "$ALERT_EMAIL"
    
    # 方式2:使用curl + SMTP(无需mail命令)
    # curl -s --url "smtp://${SMTP_SERVER}" \
    #     --ssl-reqd --mail-from "$MAIL_FROM" \
    #     --mail-rcpt "$ALERT_EMAIL" \
    #     -u "$MAIL_FROM:$MAIL_PASSWORD" \
    #     -T <(echo -e "From: $MAIL_FROM\nTo: $ALERT_EMAIL\nSubject: $subject\n\n$message")
}

完整脚本:三路同时告警

#!/bin/bash
# redirect-monitor.sh - 重定向异常多通道告警脚本
# 用法: ./redirect-monitor.sh urls.txt

# ========== 配置区 ==========
DINGTALK_TOKEN="your_dingtalk_token"
DINGTALK_SECRET="your_dingtalk_secret"
WECOM_KEY="your_wecom_key"
ALERT_EMAIL="ops@example.com"
ALLOWED_DOMAINS="www.example.com,m.example.com"
MAX_REDIRECTS=5
MAX_TIME=2

# ========== 告警防抖 ==========
ALERT_CACHE_DIR="/tmp/redirect_alert_cache"
mkdir -p "$ALERT_CACHE_DIR"

# 防止同一URL在10分钟内重复告警
check_alert_dedup() {
    local url="$1"
    local cache_file="${ALERT_CACHE_DIR}/$(echo "$url" | md5sum | cut -d' ' -f1)"
    
    if [ -f "$cache_file" ]; then
        local last_alert=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null)
        local now=$(date +%s)
        local diff=$((now - last_alert))
        
        if [ "$diff" -lt 600 ]; then
            return 1  # 10分钟内已告警过,跳过
        fi
    fi
    
    touch "$cache_file"
    return 0
}

# ========== 主流程 ==========
URL_FILE="${1:-urls.txt}"

if [ ! -f "$URL_FILE" ]; then
    echo "用法: $0 "
    echo "文件格式: 每行一个URL"
    exit 1
fi

alert_messages=""

while IFS= read -r url; do
    [ -z "$url" ] && continue
    [[ "$url" == \#* ]] && continue  # 跳过注释行
    
    result=$(check_redirect "$url" "$MAX_REDIRECTS" "$MAX_TIME")
    
    if echo "$result" | grep -q "^ALERT"; then
        if check_alert_dedup "$url"; then
            alert_messages="${alert_messages}\n- ${result#ALERT|}"
            echo "[ALERT] $result"
        else
            echo "[SKIP] 已在10分钟内告警: $url"
        fi
    else
        echo "[OK] $result"
    fi
done < "$URL_FILE"

# ========== 统一推送 ==========
if [ -n "$alert_messages" ]; then
    echo -e "\n=== 推送告警 ==="
    
    # 三路同时推送,任何一路失败不影响其他
    send_dingtalk "$alert_messages" && echo "钉钉: ✓" || echo "钉钉: ✗"
    send_wecom "$alert_messages" && echo "企业微信: ✓" || echo "企业微信: ✗"
    send_email "$alert_messages" && echo "邮件: ✓" || echo "邮件: ✗"
else
    echo "无异常,不推送告警"
fi

# ========== 清理过期缓存 ==========
find "$ALERT_CACHE_DIR" -type f -mmin +60 -delete

定时任务配置

用crontab设置每5分钟检测一次:

# 编辑crontab
crontab -e

# 每5分钟执行一次检测
*/5 * * * * /opt/scripts/redirect-monitor.sh /opt/scripts/urls.txt >> /var/log/redirect-monitor.log 2>&1

urls.txt文件格式

# 每行一个待检测URL
# #开头为注释行
https://www.example.com/promotion?utm_source=wechat
https://www.example.com/product/detail?id=123
https://m.example.com/landing?channel=baidu

告警防抖机制说明

多通道告警最大的副作用是消息轰炸。同一个URL持续异常,如果每5分钟都推3条消息,一天就是864条。所以脚本内置了防抖:

  • 同一URL 10分钟内只告警一次
  • 缓存文件1小时后自动清理
  • 恢复后第一次异常仍会正常告警

扩展方向

  • 加入Slack/Telegram通道,覆盖海外团队
  • 接入Prometheus Pushgateway,用Grafana看板展示趋势
  • 加入短信通道(阿里云SMS),处理P0级告警
  • 结合Jenkins Pipeline,发布后自动验证跳转链路

相关文章

版权声明

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

发表评论