curl 请求含方括号的 URL 时报 bad range
curl 请求中的 filter[name]、args[0] 可能被解析成 URL 范围。保留 shell 引号并使用 --globoff,或编码查询参数中的括号;同时区分参数名与值的编码,以及 -g 和 -G 的作用。
从接口工具复制出的命令,URL 已经加了引号,终端仍然报错:
curl: (3) bad range in URL position ...
如果报错箭头指向查询参数里的 [,例如 filter[name] 或 args[0],通常是 curl 把方括号当成了 URL 范围表达式。旧版本的报错还可能包含 [globbing]、bad range in column 或 unmatched close brace/bracket。只看到错误码 3 不能确定原因;这里处理的是完整 URL 中确实含有查询参数方括号的情况。
下面的命令适用于 Linux、macOS 上的 Bash、zsh 等 shell,域名和接口路径都是示例。先在允许调试的测试接口上验证,尤其不要拿创建订单、删除资源等请求试错。
URL 加引号后,curl 仍会解释方括号
shell 和 curl 各自有一层解析。引号可以让 shell 把包含 &、?、方括号的 URL 作为一个参数传递;收到这个参数后,curl 仍会执行自己的 URL globbing。
例如,curl 会把 [1-3] 解释成范围,把 {one,two} 解释成两个候选值。这项功能用于一条命令访问多个 URL。查询参数本来想传字面值 filter[name],却被送进同一个解析器,就可能在网络请求发出前失败。某些内容恰好是合法范围时,还可能展开成多次请求,而不是报错。
给 URL 反复加引号、更换终端,未必能解决 curl 报出的范围错误。若看到的是 shell 的 no matches found,则应先修正 shell 引号;不要把两层错误混在一起。
保留字面方括号时加 --globoff
如果接口接受 URL 中未编码的方括号,可以关闭这条命令的 URL globbing,同时保留引号:
curl --globoff 'https://api.example.com/items?filter[name]=demo&limit=10'
--globoff 的短选项是小写 -g,从 curl 7.6 起提供。它让 curl 不再把 URL 中的 {} 和 [] 当成展开表达式,但不会替你完成 URL 编码,也不会关闭 shell 的解析。因此,删掉引号只留下 -g,仍可能被 & 等字符打断命令。
修改现有请求时,保留原来的请求方法、认证头、请求体及必要选项,只补上 --globoff。示例是默认 GET,不能用它替换原本的 POST 请求。若原命令有意使用范围批量下载,关闭 globbing 会改变它的含义,应把那个批量任务与含字面括号的接口请求分开处理。
需要规范 URL 时编码参数名
在脚本或配置中,可以把查询参数中的方括号编码为 %5B 和 %5D:
curl 'https://api.example.com/items?filter%5Bname%5D=demo&limit=10'
这种写法不会把字面方括号交给 globbing。这里只编码参数名中的括号,URL 的 https://、分隔查询参数的 ?、& 和 = 仍有结构用途,不能把整串地址不加区分地编码。
已经编码好的 %5B 不要再手工变成 %255B。后者多了一层编码,服务端解码一次后得到的仍是 %5B,可能无法匹配预期的参数名。带签名的 URL 还应遵守接口规定的编码和签名流程,不能改完地址却沿用针对另一串地址计算的签名。
这里说的替换针对查询参数。IPv6 地址外层的方括号有不同用途,例如 https://[2001:db8::1]/;curl 会识别这种数值 IPv6 地址,不需要为了它把地址括号改成 %5B、%5D。
参数值含空格或特殊字符时分开传
手工拼接 URL 时,参数值也可能需要编码。GET 请求可以把基础 URL 与参数拆开:
curl --get 'https://api.example.com/items' \
--data-urlencode 'filter%5Bname%5D=demo item' \
--data-urlencode 'limit=10'
--get 把这些数据追加到 URL 的查询部分,使用 GET;--data-urlencode 按 name=content 语法只编码等号右侧的值。左侧参数名需要预先编码,所以这里仍写成 filter%5Bname%5D,不能指望这个选项自动处理参数名里的方括号。
等号右侧应传原始值 demo item,让 curl 编码。若提前把值写成 demo%20item 再交给它,百分号也会被编码,造成重复编码。--data-urlencode 从 curl 7.18.0 起提供;上面的完整写法不适用于更早版本。
大写 -G 是 --get,小写 -g 才是 --globoff,两者不能互换。原本要发送 POST 请求体时,也不能为了修方括号直接加 -G,否则数据位置和请求方式都会变。
核对实际发送的参数
在同一个测试接口上,为选定的修复写法临时加一次 --verbose,查看实际请求。例如编码后的简单 GET:
curl --verbose 'https://api.example.com/items?filter%5Bname%5D=demo&limit=10'
验收要确认三件事:范围解析错误消失;实际请求的路径、参数名与值正确,没有意外展开成多个目标;接口返回的内容符合过滤条件。能收到 HTTP 响应,只能证明请求走到了 HTTP 阶段。401、403 或参数校验错误还要按接口认证与参数规则处理,不能仅凭退出错误变化就算修好。
调试日志可能包含认证头、Cookie 和敏感查询参数。检查后移除 --verbose,对外提供日志前先脱敏。若改动后接口行为变了,恢复保存的旧命令,再检查是否误用了 -G、重复编码或改变了签名输入;不要同时修改请求方法和服务端配置,否则很难判断哪一步改变了结果。


