Shell脚本中通过CURL GET请求传递JSON解析变量时遭遇URL格式错误问题求助
解决curl请求URL格式错误及JSON解析问题
咱们一步步排查并修复你的脚本问题:
1. 核心错误:JSON解析方式完全错误
你当前的写法ruleId=$($whitelist | jq '.[].ruleId')是根本问题——$whitelist是文件名,不是可执行命令,shell会尝试把文件名当作命令运行,直接导致变量值异常,进而污染curl的请求参数,引发URL格式错误。
正确的做法是让jq直接读取文件,或者用cat传递文件内容给jq:
# 推荐方式:jq直接读取文件 ruleId=$(jq -r '.[].ruleId' "$whitelist") # 备选方式:用cat传递文件内容 ruleId=$(cat "$whitelist" | jq -r '.[].ruleId')
2. 必须去掉jq输出的双引号
默认情况下,jq输出的字符串会自带双引号(比如"1001"),如果直接把这个值传给curl,会导致参数里包含多余的引号,破坏请求格式。加上-r(raw output)参数可以让jq输出不带引号的纯字符串。
3. 处理JSON数组的循环问题
你的JSON是一个数组结构,.[].ruleId会输出数组中所有元素的ruleId,如果数组有多个元素,变量会被赋值为多个值用空格分隔,导致curl参数混乱。你需要循环遍历数组中的每个元素:
# 遍历JSON数组中的每个对象 jq -c '.[]' "$whitelist" | while read -r item; do # 从单个对象中提取字段,-r确保输出无引号 ruleId=$(echo "$item" | jq -r '.ruleId') alert=$(echo "$item" | jq -r '.alertName') newLevel=$(echo "$item" | jq -r '.newLevel') url=$(echo "$item" | jq -r '.url') urlIsRegex=$(echo "$item" | jq -r '.urlIsRegex') enabled=$(echo "$item" | jq -r '.enabled') parameter=$(echo "$item" | jq -r '.parameter') evidence=$(echo "$item" | jq -r '.evidence') # 执行curl请求 curl --data-urlencode "ruleId=$ruleId" \ --data-urlencode "newLevel=$newLevel" \ --data-urlencode "url=$url" \ --data-urlencode "urlIsRegex=$urlIsRegex" \ --data-urlencode "enabled=$enabled" \ --data-urlencode "parameter=$parameter" \ --data-urlencode "evidence=$evidence" \ "http://localhost:8080/JSON/alertFilter/action/addGlobalAlertFilter" done
4. 关于curl请求方法的补充说明
注意:使用--data-urlencode参数时,curl默认会发送POST请求,而非GET请求。如果你的API确实要求GET,需要手动将编码后的参数拼接到URL后:
# GET请求示例:手动编码并拼接参数 encoded_ruleId=$(printf "%s" "$ruleId" | xargs printf "%q") encoded_url=$(printf "%s" "$url" | xargs printf "%q") curl "http://localhost:8080/JSON/alertFilter/action/addGlobalAlertFilter?ruleId=$encoded_ruleId&newLevel=$newLevel&url=$encoded_url..."
不过从API路径/addGlobalAlertFilter来看,更可能接受POST请求,所以原有的--data-urlencode方式是合适的。
完整修复后的脚本
#!/bin/sh #set -e # 测试脚本说明 # 1. 启动docker # 2. 在终端运行命令:docker run -u zap -p 8080:8090 -i owasp/zap2docker-stable zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.disablekey=true -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true # 3. 从API获取JSON(当前为测试用) # 4. 执行bash filter.sh # 5. 通过浏览器http://localhost:8080/UI/alertFilter/ 查看已设置的全局过滤器 # 下载示例JSON到临时文件 curl -s 'https://api.npoint.io/c29e3a68be632f73fc22' > whitelist_tmp.json whitelist=whitelist_tmp.json # 遍历JSON数组中的每个告警规则对象 jq -c '.[]' "$whitelist" | while read -r item; do # 提取每个字段并去掉jq默认的双引号 ruleId=$(echo "$item" | jq -r '.ruleId') alert=$(echo "$item" | jq -r '.alertName') newLevel=$(echo "$item" | jq -r '.newLevel') url=$(echo "$item" | jq -r '.url') urlIsRegex=$(echo "$item" | jq -r '.urlIsRegex') enabled=$(echo "$item" | jq -r '.enabled') parameter=$(echo "$item" | jq -r '.parameter') evidence=$(echo "$item" | jq -r '.evidence') echo "正在添加规则ID为 $ruleId 的全局告警过滤器..." # 发送curl请求 curl --data-urlencode "ruleId=$ruleId" \ --data-urlencode "newLevel=$newLevel" \ --data-urlencode "url=$url" \ --data-urlencode "urlIsRegex=$urlIsRegex" \ --data-urlencode "enabled=$enabled" \ --data-urlencode "parameter=$parameter" \ --data-urlencode "evidence=$evidence" \ "http://localhost:8080/JSON/alertFilter/action/addGlobalAlertFilter" done # 清理临时文件 rm "$whitelist"
现在运行这个修复后的脚本,应该就能正常发送请求并添加全局告警过滤器了。
内容的提问来源于stack exchange,提问作者t30_9
相关产品推荐
相关产品推荐

