为什么要用JSON格式化输出重定向检测结果
做网站巡检的时候,curl的原始输出是纯文本,看起来费劲,也不好做后续处理。把结果转成JSON格式,既能让人一眼看明白,又能直接被程序解析,接入监控系统或者存数据库都很方便。
这篇文章就讲清楚:怎么用Shell脚本把curl批量检测重定向的结果格式化成JSON,覆盖3个实战场景,拿来就能用。
场景一:单条URL重定向结果输出JSON
最基本的需求——检测一个URL的重定向信息,输出一条JSON记录。
核心脚本
#!/bin/bash
# check_redirect_json.sh - 单条URL重定向检测,输出JSON
URL="$1"
RESULT=$(curl -sL -o /dev/null -w '{"url":"%{url_effective}","num_redirects":%{num_redirects},"http_code":%{http_code},"time_total":%{time_total},"redirect_url":"%{redirect_url}"}' "$URL")
echo "$RESULT" | jq .
运行效果
bash check_redirect_json.sh https://example.com
{
"url": "https://example.com/",
"num_redirects": 1,
"http_code": 200,
"time_total": 0.523,
"redirect_url": ""
}
几个要点:
- -sL:静默模式+跟随重定向,这样才能拿到最终结果
- -o /dev/null:丢弃页面内容,只关心元数据
- -w:用JSON模板格式化输出,变量直接内嵌
- jq .:美化输出,方便阅读
场景二:批量URL检测输出JSON数组
实际巡检不会只查一个URL。这个脚本从文件读取URL列表,逐个检测,最后输出一个完整的JSON数组。
脚本代码
#!/bin/bash
# batch_redirect_json.sh - 批量检测URL重定向,输出JSON数组
URL_FILE="$1"
TMPDIR=$(mktemp -d)
if [ -z "$URL_FILE" ] || [ ! -f "$URL_FILE" ]; then
echo "用法: bash batch_redirect_json.sh urls.txt"
exit 1
fi
echo "[" > "$TMPDIR/result.json"
FIRST=true
while IFS= read -r url; do
[ -z "$url" ] && continue
# 跳过注释行
[[ "$url" == \#* ]] && continue
RECORD=$(curl -sL -o /dev/null --max-time 10 -w '{"url":"'"$url"'","final_url":"%{url_effective}","redirects":%{num_redirects},"status":%{http_code},"time_sec":%{time_total}}' "$url" 2>/dev/null)
if [ "$FIRST" = true ]; then
FIRST=false
else
echo "," >> "$TMPDIR/result.json"
fi
echo "$RECORD" >> "$TMPDIR/result.json"
done < "$URL_FILE"
echo "" >> "$TMPDIR/result.json"
echo "]" >> "$TMPDIR/result.json"
# 美化输出
jq . "$TMPDIR/result.json"
rm -rf "$TMPDIR"
URL列表文件示例
# urls.txt - 网站巡检列表
https://www.example.com
https://blog.example.com
https://shop.example.com/page?utm_source=wechat
输出结果
[
{
"url": "https://www.example.com",
"final_url": "https://www.example.com/",
"redirects": 0,
"status": 200,
"time_sec": 0.312
},
{
"url": "https://blog.example.com",
"final_url": "https://blog.example.com/home",
"redirects": 1,
"status": 200,
"time_sec": 0.876
},
{
"url": "https://shop.example.com/page?utm_source=wechat",
"final_url": "https://shop.example.com/page",
"redirects": 1,
"status": 200,
"time_sec": 1.023
}
]
注意第三个结果——UTM参数在重定向后丢失了,final_url里没有utm_source。这种问题用这个脚本一目了然。
场景三:批量检测+异常筛选+结构化输出
更实用的场景:只筛选出有问题的URL(重定向次数过多、状态码非200、耗时过长),输出结构化JSON告警报告。
脚本代码
#!/bin/bash
# redirect_alert_json.sh - 重定向异常检测,输出JSON告警报告
URL_FILE="$1"
MAX_REDIRECTS=3
MAX_TIME=3.0
[ -z "$URL_FILE" ] && { echo "用法: bash redirect_alert_json.sh urls.txt"; exit 1; }
ALERTS="["
FIRST=true
while IFS= read -r url; do
[ -z "$url" ] || [[ "$url" == \#* ]] && continue
# 一次curl输出多变量,用分隔符隔开
RAW=$(curl -sL -o /dev/null --max-time 10 \
-w '\n%{url_effective}\n%{num_redirects}\n%{http_code}\n%{time_total}' "$url" 2>/dev/null)
FINAL_URL=$(echo "$RAW" | sed -n '2p')
REDIRECTS=$(echo "$RAW" | sed -n '3p')
HTTP_CODE=$(echo "$RAW" | sed -n '4p')
TIME_TOTAL=$(echo "$RAW" | sed -n '5p')
IS_ALERT=false
REASONS="[]"
# 检查重定向次数
if [ "$REDIRECTS" -gt "$MAX_REDIRECTS" ] 2>/dev/null; then
IS_ALERT=true
REASONS=$(echo "$REASONS" | jq --arg r "重定向${REDIRECTS}次超过阈值${MAX_REDIRECTS}" '. + [$r]')
fi
# 检查状态码
if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "000" ]; then
IS_ALERT=true
REASONS=$(echo "$REASONS" | jq --arg r "状态码${HTTP_CODE}异常" '. + [$r]')
fi
# 检查耗时
if [ "$(echo "$TIME_TOTAL > $MAX_TIME" | bc 2>/dev/null)" = "1" ]; then
IS_ALERT=true
REASONS=$(echo "$REASONS" | jq --arg r "耗时${TIME_TOTAL}s超过阈值${MAX_TIME}s" '. + [$r]')
fi
if [ "$IS_ALERT" = true ]; then
RECORD=$(jq -n \
--arg url "$url" \
--arg final_url "$FINAL_URL" \
--argjson redirects "$REDIRECTS" \
--argjson status "$HTTP_CODE" \
--argjson time "$TIME_TOTAL" \
--argjson reasons "$REASONS" \
'{url:$url, final_url:$final_url, redirects:$redirects, status:$status, time_sec:$time, alert_reasons:$reasons}')
if [ "$FIRST" = true ]; then
FIRST=false
else
ALERTS+=","
fi
ALERTS+="$RECORD"
fi
done < "$URL_FILE"
ALERTS+="]"
# 输出告警报告
echo "$ALERTS" | jq .
# 统计
TOTAL=$(echo "$ALERTS" | jq 'length')
echo ""
echo "告警总数: $TOTAL"
告警输出示例
[
{
"url": "https://old.example.com/promo",
"final_url": "https://www.example.com/promo",
"redirects": 5,
"status": 200,
"time_sec": 3.456,
"alert_reasons": [
"重定向5次超过阈值3",
"耗时3.456s超过阈值3.0s"
]
}
]
告警总数: 1
curl -w变量在JSON输出中的注意事项
用curl -w拼JSON的时候,有几个坑容易踩:
1. 变量值可能包含特殊字符
URL中如果有引号或反斜杠,会破坏JSON结构。解决办法:先用curl输出原始值,再用jq构造JSON对象。
# 安全写法:用jq构造JSON
FINAL_URL=$(curl -sL -o /dev/null -w '%{url_effective}' "$URL")
HTTP_CODE=$(curl -sL -o /dev/null -w '%{http_code}' "$URL")
jq -n --arg url "$URL" --arg final "$FINAL_URL" --argjson code "$HTTP_CODE" \
'{url:$url, final_url:$final, status:$code}'
2. num_redirects和http_code是数字,不要加引号
在-w模板里直接写%{num_redirects}和%{http_code},它们本身就是整数,JSON里也应该是数字类型。加引号就变成字符串了,下游程序处理会出问题。
3. 多次curl调用效率问题
上面场景三的脚本对每个URL只调用了1次curl,用分隔符输出多变量再解析。如果URL很多,这个写法比每个变量单独调用curl快好几倍。也可以配合xargs做并行加速,这个可以参考之前的文章。
把JSON结果存下来做对比
巡检数据存成JSON文件,按日期归档,可以做趋势对比:
# 按日期存储
DATE=$(date +%Y%m%d)
jq . "$TMPDIR/result.json" > "/data/redirect_report_${DATE}.json"
# 对比两天数据,找出重定向次数变化的URL
jq -s '.[0] as $today | .[1] as $yesterday |
[$today[] | select(.redirects != ($yesterday[] | select(.url == .url) | .redirects))]' \
"/data/redirect_report_${DATE}.json" "/data/redirect_report_$(date -d yesterday +%Y%m%d).json"
总结
三个场景从简单到复杂:
- 单条检测:curl -w直接拼JSON,简单粗暴
- 批量检测:循环+数组拼接,适合日常巡检
- 异常筛选:加阈值判断+告警原因,直接对接告警系统
核心就一个思路:curl负责采集数据,Shell负责拼接格式,jq负责安全和美化。三件套组合起来,网站巡检的报告想怎么格式化都行。
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论