0

curl批量重定向检测JSON输出格式化:3个实战方案让巡检数据直接可编程

2026.06.15 | youres | 6次围观

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

发表评论