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辅助作者原创,未经许可,转载请保留原文链接。

发表评论