curl 命令--data-binary完全指南:按原样 POST 二进制数据、保留换行与空字节的底层原理
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
--data-binary是 curl(命令行工具与 libcurl 传输库)用于 HTTP POST 时"按字节原样提交数据"的关键选项:它不做任何额外加工、不剥离换行与回车、也不过滤空字节。本文以仓库中该选项的官方说明 docs/cmdline-opts/data-binary.md 为骨架,结合 curl 源码中的参数解析链路,为你梳理它的语法、与--data/--data-raw/--data-urlencode的取舍、Content-Type 设置技巧,以及"数据如何从命令行进入请求体"的实现细节。
选项速览:--data-binary是什么
在 curl 中,所有以--data开头的系列选项都用于向服务器发送数据。--data-binary的官方定义极其精简,却也点出了它与其他选项最本质的差异:
Post data exactly as specified with no extra processing whatsoever. (完全按给定内容发送数据,不做任何额外处理。)
从该选项的元数据定义(见 docs/cmdline-opts/data-binary.md 开头的 front-matter)可以得到如下事实表:
| 属性 | 取值 | 说明 |
|---|---|---|
| 长选项 | --data-binary | 无短选项别名 |
| 参数 | <data> | 数据本体,或@filename/@- |
| 帮助文本 | HTTP POST binary data | 工具内置帮助同样如此描述 |
| 适用协议 | HTTP | 与--data(HTTP + MQTT)不同,仅限 HTTP |
| 分类 | http post upload | 属于 HTTP 表单提交 / 上传家族 |
| 引入版本 | 7.2 | 相当古老的选项,早已是稳定行为 |
| Multi 属性 | append | 可重复使用,多次指定的数据会拼接 |
curl 命令行工具内置的帮助列表也做了同步维护,可在 src/tool_listhelp.c 中看到--data-binary <data>的条目。
核心差异:什么叫做"不做任何额外处理"
理解--data-binary的最好方式,是与同族的其他选项对照。curl 对@前缀和换行/空字节的处理在各选项间并不一致,这正是选择--data-binary的真正理由。
与--data的对比:保留换行、回车与二进制
官方文档>curl --data-binary @filename $URL
一个更接近真实用途的示例——上传 JSON 文件并显式声明媒体类型:
curl --data-binary @data.json \ -H "Content-Type: application/json" \ https://api.example.com/v1/ingestContent-Type:默认表单编码,如何切换为任意二进制
与--data相同,--data-binary默认发送给服务器的 Content-Type 是application/x-www-form-urlencoded。这是历史兼容行为,意味着如果你不额外指定头,服务器即便收到的是二进制内容,也会先按 URL 编码表单来理解请求体。
如果你希望服务器把数据当作**任意二进制(arbitrary binary data)**处理,文档给出的做法是显式覆盖该请求头:
curl --data-binary @blob.bin \ -H "Content-Type: application/octet-stream" \ https://upload.example.com/raw实际项目中也常出现Content-Type: application/json、application/pdf、application/x-protobuf等覆盖写法,原理一致:-H中显式声明的 Content-Type 会覆盖选项内置的默认值。
多次使用的拼接语义(Multi: append)
选项元数据中的Multi: append意味着--data-binary可以重复出现,并且数据会按顺序累积。拼接规则继承自--data(docs/cmdline-opts/data.md 有完整描述):
If any of these options is used more than once on the same command line, the data pieces specified are merged with a separating &-symbol. Thus, using
-d name=daniel -d skill=lousywould generate a post chunk that looks likename=daniel&skill=lousy.
翻译成--data-binary的等价行为:
# 最终请求体等价于 name=daniel&skill=lousy curl --data-binary "name=daniel" --data-binary "skill=lousy" $URL这个&拼接对表单拼接很友好,但对二进制文件分块投递不友好:如果一段二进制数据里恰好含有&字节,拼接语义仍会原样保留它(--data-binary不会改写你的字节),只是在多次指定时,curl 会在两段数据之间主动插入一个&。因此,需要投递单个完整二进制文件的场景,请只使用一次--data-binary @file,不要拆成多段。
源码级原理:从命令行参数到请求体的调用链
步骤一:参数表注册
在命令行解析器 src/tool_getparam.c 中,--data-binary被注册为无短选项、参数类型为字符串的选项,并映射到内部枚举C_DATA_BINARY:
{"data-binary", ARG_STRG, ' ', C_DATA_BINARY},步骤二:统一分发到 set_data()
在 src/tool_getparam.c 处,--data、--data-ascii、--data-binary、--data-urlencode、--json、--data-raw全部汇入同一个处理函数set_data(),这正是各选项行为相近、仅在细节上分野的原因。
步骤三:@前缀与文件读取分支
核心逻辑位于 src/tool_getparam.c 的set_data():
else if('@' == *nextarg && (cmd != C_DATA_RAW)) { /* the data begins with a '@' letter, it means that a filename or - (stdin) follows */ nextarg++; /* pass the @ */ ... if(cmd == C_DATA_BINARY) /* forced>if(curlx_dyn_len(&config->postdata)) { if(!err && (cmd != C_JSON) && curlx_dyn_addn(&config->postdata, "&", 1)) err = PARAM_NO_MEM; } ... config->postfields = curlx_dyn_ptr(&config->postdata);这段代码从实现层面印证了"多次使用以&拼接"的文档语义,也解释了为什么--json不参与&拼接(JSON 载荷不适用表单分隔符)。累积完成的config->postfields指针随后会被传给 libcurl 的传输层选项CURLOPT_POSTFIELDS/CURLOPT_COPYPOSTFIELDS,其接收逻辑位于库侧 lib/setopt.c,配合 lib/setopt.c 处的CURLOPT_POSTFIELDSIZE_LARGE一起,libcurl 才能真正按字节长度(而非strlen)发送含空字节的二进制请求体。
调用链小结
--data-binary @file → src/tool_getparam.c 选项表 (C_DATA_BINARY) → getparameter() 分发 (case C_DATA_BINARY) → set_data() ├─ '@' 判定 → rb 打开文件 / 对 stdin 置二进制模式 ├─ file2memory() → 完整保留换行/回车/空字节 └─ dynbuf postdata 累积(多次指定时插入 '&') → config->postfields → libcurl CURLOPT_POSTFIELDS / CURLOPT_POSTFIELDSIZE (lib/setopt.c) → HTTP POST 请求体实用示例集合
把上面的规则串起来,下面这些命令都值得收藏:
1. 从文件原样提交文本/JSON(保留所有换行缩进):
curl --data-binary @payload.json \ -H "Content-Type: application/json" \ https://httpbin.org/post2. 提交任意二进制并告知服务器为字节流:
curl --data-binary @model.bin \ -H "Content-Type: application/octet-stream" \ https://upload.example.com/files3. 从标准输入管道读取:
cat screenshot.png | curl --data-binary @- \ -H "Content-Type: application/octet-stream" \ https://upload.example.com/images4. 直接内联 POST 二进制安全的字符串:
curl --data-binary "line1 line2" https://example.com/echo(注意:内联模式下换行由 shell 引号内的真实换行决定,curl 原样发送。)
注意事项与易错点
- 协议范围仅为 HTTP:
--data-binary的协议标记是 HTTP,而--data还支持 MQTT(数据以 PUBLISH 语义发送)。涉及 MQTT 的载荷请使用--data家族而非--data-binary。 - 二进制文件请单次指定:多次使用会插入
&分隔,可能污染二进制流。 - 空字节需要配合正确的 Content-Type 与接收方:默认
application/x-www-form-urlencoded下服务器可能拒绝或误解析,请显式覆盖请求头。 @冲突:如果待投递内容本身以@开头且不想触发文件读取,请改选--data-raw(它放弃@解释,也不保留"读文件路径");如果必须从文件读取,--data-binary是正确选择。- 使用场景判断:需保留换行、回车的文本(如格式化 JSON、多行报文),以及含空字节的任意二进制(图片、压缩包、序列化数据),都是
--data-binary的典型适用面;普通键值对表单则优先--data/--data-urlencode。
延伸阅读
- 官方选项说明:docs/cmdline-opts/data-binary.md
- 同族选项:docs/cmdline-opts/data.md、docs/cmdline-opts/data-raw.md、docs/cmdline-opts/data-ascii.md、docs/cmdline-opts/data-urlencode.md
- 命令行解析实现:src/tool_getparam.c
- 内嵌帮助文本生成:src/tool_listhelp.c
- libcurl 侧请求体选项处理:lib/setopt.c
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考