curl-d, --data选项完全指南:HTTP POST 与 MQTT PUBLISH 数据发送全解析
【免费下载链接】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
导读
-d, --data <data>是 curl 命令行工具中最常用也最核心的数据发送选项之一:它让 curl 以浏览器提交 HTML 表单的方式向 HTTP(S) 服务器发送 POST 请求,同时也是 MQTT 场景下发布消息数据的方式。本文将围绕 curl 源码仓库中该选项的权威文档 docs/cmdline-opts/data.md 展开,完整解读其语义、@文件读取规则、多次追加时的拼接行为、与--data-raw/--data-binary/--data-urlencode等变体的取舍,并结合命令行解析源码(src/tool_getparam.c)揭示其底层实现,帮助你在日常接口调试、表单提交与自动化脚本中精确控制发送的数据内容。
选项速览与适用范围
--data的完整元数据(记录于 docs/cmdline-opts/data.md 的文件头)如下:
- 长选项:
--data - 短选项:
-d - 参数:
<data> - 帮助文本:Post data
- 适用协议(Protocols):HTTP MQTT
- 互斥选项(Mutexed):
form、head、upload-file,即与-F/--form、-I/--head、-T/--upload-file在同一命令行中不可同时生效 - 分类(Category):important http post upload mqtt
- 添加版本(Added):4.0(即自 curl 4.0 起就存在,是最古老的选项之一)
- 多次使用行为(Multi):append,即同一命令行多次给出时按追加语义合并
- See-also:
--data-binary、--data-urlencode、--data-raw、--form
三个官方示例奠定了本文讨论的基础:
curl -d "name=curl" $URL curl -d "name=curl" -d "tool=cmdline" $URL curl -d @filename $URL值得注意的是,docs/cmdline-opts/目录下的每个.md文件并不是给普通用户阅读的独立说明,而是 curl 手册页(curl.1)的源文件:构建系统通过 scripts/managen 脚本按 docs/cmdline-opts/MANPAGE.md 中描述的格式把它们渲染为 nroff/man 文档。因此,本文中针对--data的描述与你在man curl、curl --help中看到的内容同源。
HTTP(S) 下的 POST 语义:与表单提交一致
对于 HTTP(S) 协议,--data使用POST 方法发送数据,其行为与用户填写完 HTML 表单后点击提交按钮时浏览器发出的请求完全一致:
- 数据被放入请求体(request body);
- curl 默认携带的 Content-Type 为
application/x-www-form-urlencoded,这正是浏览器标准表单的编码类型。
因此下面这条命令:
curl -d "name=curl&tool=cmdline" https://example.com/submit在语义上等价于用户在表单中输入了name=curl与tool=cmdline两个字段并提交。服务器端按标准表单解析方式即可读取字段。
如果你需要改变 Content-Type,可以借助-H/--header显式覆盖,例如把数据当作纯文本或 JSON 处理:
# 以 text/plain 语义提交(服务器不会按表单解析) curl -d "hello world" -H "Content-Type: text/plain" $URL # 以 JSON 语义提交(配合字符串化的 JSON) curl -d '{"name":"curl"}' -H "Content-Type: application/json" $URL注意:
--data本身只负责「把字节原样放进请求体并声明默认编码」,它不会为你转义或序列化 JSON,请自行确保 payload 的格式正确。
数据原样传递:curl 不做任何“改善”
原文档特别强调了一个容易被忽略的事实:
The data for this option is passed on to the server exactly as provided on the command line. curl does not convert, change or improve it. It is up to the user to provide the data in the correct form.
即:--data的参数会原样、逐字节传递给服务器,curl 不会转换、修改或“优化”你的数据——URL 编码也好、字段分隔也好,都需要使用者自己保证格式正确。这条约束解释了为什么 curl 家族还需要--data-urlencode(替你编码)与--data-binary(保留换行等原始字节)这两个变体。
MQTT 场景:数据以 PUBLISH 消息发送
--data的 Protocols 元数据是HTTP MQTT,这说明它同样适用于 MQTT(Message Queuing Telemetry Transport)协议。在 MQTT 请求中:
- 主题(topic)由 URL 的路径部分给出;
--data携带的内容作为PUBLISH报文发布到该主题。
# 向 MQTT broker 的 test/topic 主题发布一条消息 curl -d "hello from curl" mqtt://broker.example.com/test/topic这是 curl 在 docs/cmdline-opts/data.md 与 MQTT 支持(实现位于 lib/mqtt.c)之间的一条明确对应关系:命令行给出的数据即发布内容。
核心规则一:@前缀与从文件/标准输入读取数据
如果--data的参数以字母@开头,那么@之后的剩余部分被解释为文件名,curl 将读取该文件的内容作为 POST 数据;若@后跟-,则从**标准输入(stdin)**读取。
# 从文件 foobar 读取数据并 POST curl --data @foobar $URL # 从标准输入读取(例如管道输入) echo "name=curl" | curl -d @- $URL # 从 stdin 读取时也可省略为显式写法 cat payload.txt | curl -d @- https://example.com/submit一个关键的处理细节是:当--data从文件读取数据时,回车符(carriage returns)、换行符(newlines)与空字节(null bytes)会被剥除(详见下节源码分析)。如果文件内容是跨多行的文本,这些换行会被去掉,拼接进请求体。
如果不希望@具有这种特殊含义,改用--data-raw,它会把@当作普通字符处理(见后文)。
核心规则二:多次使用以&自动拼接
--data的 Multi 元数据为append:若在同一条命令行中多次使用该选项(或其追加类变体),curl 会把各部分数据用&符号连接合并为一个整体,然后再发送。
原文档给出了最直白的例子:同时使用-d name=daniel -d skill=lousy,最终生成的请求体是:
name=daniel&skill=lousycurl -d name=daniel -d skill=lousy $URL # 等效于: curl -d "name=daniel&skill=lousy" $URL这种写法让脚本可以通过多次-d逐步累积表单字段,而不必手工拼接长字符串。它也是表单字段多、可读性优先时推荐的命令行组织方式。需要留意:拼接规则对数据是「追加」,因此文件读取(-d @file)与其他字面量混用时同样按此规则连接。
源码级实现:命令行解析到请求体的完整链路
选项表与统一分发
curl 工具侧把所有命令行选项集中登记在 src/tool_getparam.c 的选项表中。与--data相关的登记项包括:
- 第 106 行:
{"data", ARG_STRG, 'd', C_DATA}—— 注册长名--data、短名-d,枚举C_DATA; - 第 109 行:
{"data-raw", ARG_STRG, ' ', C_DATA_RAW}; - 以及对应的
--data-ascii、--data-binary、--data-urlencode、--json等条目。
在参数分发逻辑中(src/tool_getparam.c),C_DATA、C_DATA_ASCII、C_DATA_BINARY、C_DATA_URLENCODE、C_JSON、C_DATA_RAW六个分支被统一汇聚到同一个处理函数set_data()。也就是说,整个-d家族共享同一套「读取输入 → 预处理 → 追加合并」的基础逻辑,差异只在预处理阶段。
set_data()的分支处理
set_data()(src/tool_getparam.c)的核心逻辑可以概括为三路分支:
--data-urlencode专用路径:先调用data_urlencode()完成 URL 编码,再进入合并逻辑;- 以
@开头且不是--data-raw:跳过@后,若剩余为-则使用stdin,否则以二进制只读方式curlx_fopen(name, "rb")打开文件读取。这里有一个重要的内部差异:- 对于普通
--data(file2string路径),读取后按 C 字符串处理,因此换行、回车、空字节会被剔除; - 对于
--data-binary与--json(file2memory路径),读取的是原始字节并记录长度,不做任何清洗,这正是--data-binary能携带任意二进制内容的原理; - 如果文件内容为空,
set_data()会补一个空字符串,确保仍然以 POST 形式发起请求;
- 对于普通
- 其余普通参数:直接作为字符串存入,允许空白。
追加合并与&的来源
config->postdata是一个动态增长的缓冲区(在 src/tool_cfgable.c 中通过curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY)初始化)。在set_data()尾部可以看到追加语义的实现(src/tool_getparam.c):若缓冲区中已有数据,就先用curlx_dyn_addn(&config->postdata, "&", 1)追加一个&字符,再写入本次数据——这就是「多次-d之间以&连接」的代码出处。注意--json被排除在&追加之外,避免破坏 JSON 语法。
进入 libcurl 请求
合并完成的postdata最终通过 libcurl 的CURLOPT_POSTFIELDS/CURLOPT_POSTFIELDSIZE_LARGE选项挂到 easy handle 上,这一点可以从--libcurl代码生成映射文件 src/config2setopts.c 中得到印证:它会把命令行配置翻译为对应的curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ...)调用。到这一步,--data的字节流才真正成为 HTTP POST 请求体或 MQTT PUBLISH 报文。
变体辨析:--data-raw/--data-binary/--data-urlencode
curl 围绕--data提供了一组语义微调的变体。下表汇总了各自差异(依据各选项独立文档 data.md、data-raw.md、data-binary.md、data-urlencode.md):
| 选项 | 与--data的关系 | @特殊解释 | 内容处理 |
|---|---|---|---|
--data/-d | 基准选项 | 是(@file、@-读文件/标准输入) | 从文件读取时剥除回车、换行与空字节;默认 Content-Typeapplication/x-www-form-urlencoded |
--data-ascii | 老式别名,行为与--data完全一致 | 是 | 同上(7.2 加入) |
--data-raw | 几乎相同 | 否,@按普通字符处理 | 即使内容是@at@at@也不会去读文件(7.43.0 加入) |
--data-binary | 二进制版本 | 是 | 换行/回车保留,不做任何转换;文件内容按原始字节发送(7.2 加入);如需服务器按二进制处理可加-H "Content-Type: application/octet-stream" |
--data-urlencode | 编码版本 | 是 | 先对内容做 URL 编码再发送(7.18.0 加入),用于替代手工转义表单字段 |
对应地,在 src/tool_getparam.c 的实现中:
C_DATA_RAW是唯一一个跳过@分支的选项——它直接走「普通字符串」路径,因此@失去特殊含义;C_DATA_BINARY(以及C_JSON)在读取文件时走二进制保真路径;C_DATA_URLENCODE先经data_urlencode()编码。
需要 URL 编码时使用--data-urlencode
当字段值包含空格、中文、&、=等需要在 URL 编码层面转义的字符时,应优先使用--data-urlencode。它支持五种语法(详见># 名值对编码:name 视为已编码,value 被编码 curl --data-urlencode "name=Daniel Stenberg" $URL # 只编码内容,不带 name curl --data-urlencode "=content with spaces" $URL # 从文件编码(内容含换行也会被编码) curl --data-urlencode name@file.txt $URL # 仅文件编码 curl --data-urlencode @fileonly.txt $URL # stdin 作为文件来源 echo "some data" | curl --data-urlencode @- $URL
在--data-urlencode的语法匹配中,若 content 部分本身含有=或@,会与其它语法规则产生歧义,文档建议谨慎避免,或改用前两条以=开头的无 name 形式。
二进制保真选--data-binary
如果数据中含有换行符、回车符、空字节等必须逐字节保真的二进制内容,应当使用--data-binary:
# 原样发送图片等二进制文件(注意 @ 前缀) curl --data-binary @photo.jpg $URL # 从 stdin 读取并原样发送 cat binary.bin | curl --data-binary @- $URL # 如希望服务器按任意二进制处理,显式指定 octet-stream curl --data-binary @photo.jpg -H "Content-Type: application/octet-stream" $URL--data-binary的默认 Content-Type 与--data一致(application/x-www-form-urlencoded),因此文档建议在传输二进制内容时用-H覆盖为application/octet-stream。
纯字面量选--data-raw
当你需要发送以@开头、含@的普通文本(如邮件地址、AT 命令、路径)而不希望 curl 尝试打开文件时:
# 不会去读文件 "at@at@at",而是原样 POST 该字符串 curl --data-raw "@at@at@" $URL # 与上述完全等价的另一写法 curl --data-raw "hello" $URL与其它选项的互斥关系
--data与三个选项互斥(元数据Mutexed: form head upload-file),即在一个命令行中它和以下选项的语义冲突:
-F, --form(multipart/form-data 表单,见 form.md):-F走的是 MIME/multipart 编码路径,与application/x-www-form-urlencoded的普通 POST 相互排斥;-I, --head:HEAD 方法不携带请求体;-T, --upload-file:PUT/上传语义,与 POST 冲突。
当普通-d数据、@file读取与这些选项混用时,以参数解析阶段实际生效的请求类型为准——使用--data意味着请求会被置为 POST 语义。
常见实践与避坑清单
- 提交表单字段:多个字段分多条
-d写,由 curl 自动以&连接,可读性与可维护性最好:curl -d name=curl -d tool=cmdline -d version=$(curl --version | head -1) $URL - POST 空数据:
-d ''也能发起一个空请求体的 POST;文件为空时 curl 同样会保证 POST 仍被发送(见set_data()中对空文件补""的逻辑)。 - 不要指望 curl 帮你编码:
--data是“所见即所得”的传输,需要 URL 编码请显式用--data-urlencode,需要二进制保真请用--data-binary,需要字面@请用--data-raw。 - 注意 Shell 引号:参数中含空格、
&、$等字符时务必加引号,避免被 Shell 提前解释或拆分成多条参数。 - 确认方法:
-d会自动把请求切换为 POST;若想观察实际发出的请求(含 Content-Type 与请求体),可配合curl -v查看输出,或使用--trace-ascii -查看完整字节流。 - 文档同源:本文所有语义均可在 docs/cmdline-opts/data.md 及其变体文档中交叉验证,命令行解析与合并行为可对照 src/tool_getparam.c 的
set_data()实现。
小结
-d, --data是 curl 在 HTTP(S) 上发起标准表单式 POST、在 MQTT 上发布 PUBLISH 消息的入口选项,核心行为可以归纳为三点:以application/x-www-form-urlencoded语义发送、多次使用以&自动拼接、@前缀触发文件/标准输入读取(并从文件数据中剥除换行、回车与空字节)。理解了这些规则后,再结合--data-raw(关闭@解释)、--data-binary(二进制保真)与--data-urlencode(自动 URL 编码)三个变体,你就能在任何需要“向服务器发送数据”的 curl 场景中精确控制请求体的每一字节。
【免费下载链接】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),仅供参考