🎯 一款可定制、具备反检测功能的云浏览器,由自主研发的 Chromium驱动,专为网页爬虫AI 代理设计。👉立即试用
返回博客

如何使用 cURL 发送 JSON:-d、--json 及常见错误的完整指南

Sophia Martinez
Sophia Martinez

Specialist in Anti-Bot Strategies

02-Jun-2026

主要收获:

  • 使用 cURL 发送 JSON 是两件事,而不是一件。 你将 JSON 主体附加到请求中,并通过 Content-Type: application/json 头告诉服务器这是一种 JSON。如果跳过头,很多 API 会拒绝或者错误解析主体。
  • -d/--data 传递有效负载;头由你负责。 经典模式是 curl -X POST -H "Content-Type: application/json" -d '{...}' URL-d 本身并不会设置任何 JSON 头。
  • --json 是现代快捷方式。 在 curl 7.82.0 中新增,--json '{...}' 发送主体,并通过一个标志同时设置 Content-Type: application/jsonAccept: application/json
  • Shell 引号是大多数人出错的地方。 用单引号包裹 JSON,这样 shell 不会吞掉内部的双引号;在 Windows cmd 中规则不同,使用有效负载文件更安全。
  • @file 从磁盘读取主体——但选择正确的数据标志。 -d @body.json 删除换行;--data-binary @body.json--json @body.json 按字节发送文件。
  • 相同的请求形状驱动真实的 API。 向托管 Scrapeless MCP 端点发出的 JSON-RPC 调用只是一个带有 JSON 主体和身份验证头的 POST——这正是本指南教授的确切模式。
  • 免费开始。 新的 Scrapeless 账户包括免费爬取浏览器运行时和居民代理访问——请在 Scrapeless 注册。

介绍:每个 API 集成开始的请求

几乎所有现代 web API 都支持 JSON。你用 JSON 主体进行身份验证,用 JSON 主体提交作业,在 MCP 服务器上用 JSON 主体调用工具。在这些操作在脚本或 SDK 内部运行之前,通常在终端中以单个 curl 命令开始——确认端点按文档所述行为的最快方式。

问题在于“使用 curl 发送 JSON”隐藏了两个容易混淆的独立要求。一是将 JSON 文本附加为请求主体。另一个是通过 Content-Type 头声明主体 JSON,以便服务器正确解析,而不是将其视为表单数据。将主体搞对但忘记头部,严格的 API 会返回 400 或者默默读取无效信息。在 shell 中错误引用 JSON,curl 就会发送一个本来就不是有效 JSON 的扭曲字符串。

本指南明确了“使用 curl 发送 JSON”的确切含义,讲解了执行此操作的两个标志系列(-d 加头部和更新的 --json),展示了可以对公共回显端点运行的示例,并记录了产生混淆错误的常见错误。最后通过将相同的请求形状映射到对 JSON API 的真实调用——托管的 Scrapeless MCP 端点——来结束,以便这一模式能直接从终端传递到生产环境。有关相关背景,请参阅我们关于 async HTTP 抓取的 aiohttp 指南 和有关 SSL 代理的解释


“使用 cURL 发送 JSON”的含义

cURL(围绕 libcurl 的命令行工具)通过 HTTP 和许多其他协议传输数据。“使用 cURL 发送 JSON”意味着发出一个 HTTP 请求——几乎总是 POSTPUTPATCH——其 请求主体 是一个 JSON 文档,Content-Type 被设置为 application/json

这两部分是独立的,且都很重要:

  • 主体 是原始 JSON 文本——例如 {"product":"laptop","max_price":1200}。curl 会逐字发送这些字节作为请求实体。
  • Content-Type 告诉服务器如何解释这些字节。没有它,curl 的 -d 默认是 application/x-www-form-urlencoded,这是用于 HTML 表单提交的格式。看到该头的 JSON API 可能会拒绝请求或试图(并失败)将主体解析为表单字段。

因此,正确的 JSON 请求总是将 JSON 主体与 JSON 内容类型配对。唯一的问题是你使用哪个 curl 标志来产生这种配对——这就是经典的 -d 加头部的方法与下面介绍的单标志 --json 快捷方式之间的区别。

一个快速的术语说明:-d--data 的简写,-H--header 的简写。它们可以互换使用;本指南在示例中使用简写,并在有帮助的地方命名长形式。


方法 1:-d / --data 搭配 Content-Type 头

这是通用且处处有效的方法,也是 API 文档中最常见的方式。你用 -d 提供主体,用 -H 提供头部:

bash Copy
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"product":"laptop","max_price":1200}'

正在发生三件事:

  • -X POST 设置了 HTTP 方法。严格来说,-d 已经暗示了 POST,因此此处的 -X POST 是可选的——但声明它使意图明确,如果你以某种方式切换主体标志导致默认使用 GET,则是必需的。
  • -H "Content-Type: application/json" 声明了主体格式。
  • -d '{...}' 附加了 JSON。单引号防止 shell 解析 JSON 内的双引号。

将此请求发送到 httpbin.org/post — 一个回显它收到的任何内容的公共端点 — 返回:

json Copy
{
  "data": "{\"product\":\"laptop\",\"max_price\":1200}",
  "headers": {
    "Accept": "*/*",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "curl/8.18.0"
  },
  "json": {
    "max_price": 1200,
    "product": "laptop"
  },
  "origin": "203.0.113.10",
  "url": "https://httpbin.org/post"
}
// 字段值是示例;结构是 httpbin 返回的内容。

成功的关键信号是 json 对象:只有在主体解析为有效 JSON 并且 Content-Typeapplication/json 时,httpbin 才会填充它。Accept 头为 */* — curl 的默认值 — 因为 -d 不会影响 Accept。请注意,单独使用 -d 并不会设置 任何 JSON 头:上面的 Content-Type 仅因为你添加了 -H 行而存在。去掉该行,httpbin 将报告 Content-Type: application/x-www-form-urlencoded 和一个空的 json 字段。


方法 2:--json 标志(curl 7.82.0+)

--json 标志在 curl 7.82.0(2022 年初发布)中引入,将常见情况简化为一个选项。使用 curl --version 检查你的版本;如果报告 7.82.0 或更新,--json 就可用。

bash Copy
curl -X POST https://httpbin.org/post \
  --json '{"product":"laptop","max_price":1200}'

单个 --json 同时完成三项工作。它将提供的文本作为请求主体发送,并为你设置 这两个 头:

  • Content-Type: application/json
  • Accept: application/json

第二个头是与方法 1 的实际区别:--json 还告诉服务器你 希望 返回 JSON,这些 API 用来选择它们的响应格式。通过 httpbin 回显请求确认了这一点:

json Copy
{
  "data": "{\"product\":\"laptop\",\"max_price\":1200}",
  "headers": {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "curl/8.18.0"
  },
  "json": {
    "max_price": 1200,
    "product": "laptop"
  },
  "origin": "203.0.113.10",
  "url": "https://httpbin.org/post"
}
// 注意现在 Accept 和 Content-Type 都是 application/json。

你可以多次传递 --json,curl 会将片段合并为一个主体——这对于从多个部分组装有效负载很方便。如果需要 覆盖 --json 设置的某个头(比如,其他的 Accept),在其后添加显式的 -H;后定义的头优先。

何时使用每种方法?在当前 curl 上的新作业中使用 --json。当你必须支持旧版 curl 构建时,或者当你想完全控制存在的头时,或者当你遵循的文档以这种方式编写时,使用 -d-H

行为 -d '{...}' -d '{...}' -H "Content-Type: application/json" --json '{...}'
作为主体发送 JSON
默认 HTTP 方法 POST POST POST
设置 Content-Type: application/json 否(默认为表单编码) 是(你设置了它) 是(自动)
设置 Accept: application/json 是(自动)
最小 curl 版本 任意 任意 7.82.0

免费计划 上获取你的 API 密钥:Scrapeless


使用 @ 发送 JSON 文件

以内联 JSON 的字段数超过几个后就变得笨重,较大的有效负载应该放在文件中。-d--json 都接受 @ 前缀,以从路径读取主体。考虑一个名为 body.json 的文件,如下:

json Copy
{
  "product": "laptop",
  "max_price": 1200
}

你可以使用任一标志发送它:

bash Copy
# 经典:数据标志 + 显式头
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d @body.json

# 现代:一个标志
curl -X POST https://httpbin.org/post \
  --json @body.json

读取文件的方式有一个微妙但重要的区别。-d @body.json 从文件中去掉换行符和回车符 — 这是因为 -d 是为表单数据设计的。到达服务器的主体会变成 { "product": "laptop", "max_price": 1200}:仍然是有效的 JSON(令牌之间的空白是允许的),但不再是与磁盘上的字节逐字相同。

两个标志可以精确保留文件:

bash Copy
# --data-binary 保留每个字节,包括换行符
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  --data-binary @body.json

# --json @file 也按原样发送文件
Copy
curl -X POST https://httpbin.org/post \
  --json @body.json

对于普通的 JSON,剥离换行符的版本仍然可以解析,因此 -d @file 通常有效。但是,如果有效负载必须逐字与文件匹配(签名是根据确切的字节计算的,或者文件包含具有意义的嵌入换行符的字符串值),则可以使用 --data-binary @file--json @file

您还可以通过使用 @- 从标准输入管道传输主体,这在另一个程序生成 JSON 时很方便:

bash Copy
generate_payload | curl -X POST https://httpbin.org/post --json @-

常见错误(及如何避免)

这些错误会把五秒钟的 curl 变成调试会话。

1. 忘记 Content-Type 头部

最常见的错误。使用普通的 -d 而没有头部,curl 会发送 Content-Type: application/x-www-form-urlencoded。然后 JSON API 要么拒绝请求(返回 4xx),要么读取空的主体。解决方案: 添加 -H "Content-Type: application/json",或切换到 --json,它会为您设置。

2. Shell 引号破坏 JSON

JSON 使用双引号;大多数 shell 也用双引号进行插值。将有效负载用双引号包裹会让 shell 在 curl 看见它之前清除或扩展其中的部分内容:

bash Copy
# 错误的示例:shell 消耗了内部的双引号
curl -X POST https://httpbin.org/post --json "{"product":"laptop"}"

# 正确的:用单引号包裹整个有效负载
curl -X POST https://httpbin.org/post --json '{"product":"laptop"}'

解决方案: 在 bash/zsh 上用单引号包裹整个 JSON 文档。如果某个值本身必须包含字面单引号,请转义它,或者将有效负载放入文件中并使用 @file — 这样完全避免了 shell 引号问题。

3. Windows cmd 引号处理不同

Windows cmd.exe 不将单引号视为引号字符,因此单引号技巧在此失效。您要么使用反斜杠转义每个内部双引号,要么 — 更可靠的方式 — 将 JSON 放入文件中并发送 @body.json。PowerShell 有自己的引号规则,其 curl 别名历史上指向 Invoke-WebRequest;显式调用 curl.exe,并优先使用 @file 形式来避免意外。解决方案: 在 Windows 上,使用负载文件 @body.json

4. 让 -G 将主体变成查询字符串

-G/--get 告诉 curl 将 -d 数据作为查询参数附加到 URL,而不是发送主体。这是 GET 请求的正确工具,但如果您在尝试 POST JSON 时保留它,您的有效负载会默默地转移到 URL 中,主体则为空。解决方案: 不要将 -G 与 JSON 主体结合使用;使用 -X POST(或让 -d/--json 默认转为 POST)。

5. 发送无效的 JSON

curl 不验证主体 — 它发送您提供的任何文本。尾随逗号、未加引号的键或单引号字符串都是服务器会拒绝的内容,通常会返回不透明的解析错误。解决方案: 在发送之前验证有效负载。使用 JSON 解析器的快速本地检查可以捕获大多数问题:

bash Copy
# 在 curl 运行之前快速检查无效 JSON
echo '{"product":"laptop","max_price":1200}' | python -c "import sys, json; json.load(sys.stdin); print('valid')"

6. 忘记 Accept 当 API 内容协商时

一些 API 会返回 XML 或 HTML,除非您请求 JSON。使用 -d 时,您只设置了 Content-Type,而不是 Accept,因此响应可能不是 JSON,即使您的请求是。解决方案: 添加 -H "Accept: application/json",或使用 --json,它会为您设置 Accept


示例:调用 JSON API

把这些结合起来,这里是一个真实 JSON API 调用的示例。托管的 Scrapeless MCP 端点通过 HTTP 进行 JSON-RPC 通信 — 也就是说,它就是您一直在构建的请求:一个带 JSON 主体和身份验证头的 POST。从环境变量中读取 API 密钥,以便它不会出现在您的 shell 历史记录中:

bash Copy
# 主体保存在 init.json 中;密钥来自环境,而不是命令行
curl -X POST "https://api.scrapeless.com/mcp" \
  -H "x-api-token: ${SCRAPELESS_API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data-binary @init.json

其中 init.json 存储 JSON-RPC 握手:

json Copy
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": { "name": "curl-demo", "version": "1.0" }
  }
}

每个概念在本指南中都存在:一个 JSON 正文(这里来自一个文件,使用 --data-binary 原样发送),标记其为 JSON 的 Content-Type: application/json 头,一个命名您将接受的格式的 Accept 头,以及携带凭证的身份验证头。托管的端点大约提供两打工具 — google_searchscrape_htmlscrape_markdown,浏览器自动化集 browser_* 等 — 每个工具都通过相同的 POST-a-JSON-body 模式调用,只有 methodparams 变化。具体设置详细信息请参见 Scrapeless 文档

当然,您不必一直用原始 curl 与端点交谈 — 但首先用 curl 验证端点,然后将经过验证的请求移植到您选择的语言中,是节省时间的工作流程。有关 MCP 服务器的完整工具目录和工作代理提示,请参见 5 个 Scrapeless MCP 用例


Scrapeless 的适用性

一旦 curl 命令有效,下一步通常是进行大规模请求 — 针对使用 JavaScript 渲染内容的网站或屏蔽自动化流量的网站。这就是您刚刚学习的请求结构与管理基础架构相遇的地方。

Scrapeless 提供了一个 反检测云浏览器 — Scrapeless 爬虫浏览器 — 和 超过 195 个国家的住宅代理,可通过托管的 MCP 端点、SDK 和 CLI 访问。浏览器在云端渲染 JavaScript 密集型页面并管理指纹,因此您在 curl 中原型化的干净 JSON 请求将返回结构化数据,而不是挑战页面。传输细节 — 固定住宅出口,保持会话 — 将为您处理;您这一侧保持简单的“POST 一个 JSON 正文,读取 JSON 回来”的循环。

探索 爬虫浏览器产品,在 定价页面 上查看计划,并在 文档 中找到 API 和 MCP 参考。


结论

使用 curl 发送 JSON 的关键在于两个要求共同完成:将 JSON 附加为请求正文,并通过 Content-Type 头声明它为 JSON。经典的方式是 -d '{...}' 加上 -H "Content-Type: application/json";现代的一种标志方式是 --json '{...}',它为您设置 Content-TypeAccept,适用于 curl 7.82.0 及更高版本。将大型或已签名的有效负载移入文件并使用 --data-binary @file--json @file 发送,以保留每个字节,在 bash 中单引号包裹内联 JSON 以避免 shell 引号的影响,并在 Windows 上使用有效负载文件。相同的请求 — 正文加内容类型加身份验证头 — 精确体现了调用真实 JSON API(如 Scrapeless MCP 端点)的样子,这就是为什么在您终端中有效的 curl 能够顺利移植到生产环境中。有关相关阅读,请查看 使用 aiohttp 的异步 HTTP 爬取什么是 SSL 代理


常见问题

问:使用 curl 发送 JSON 的最简单方法是什么?

在当前的 curl(7.82.0 或更新版本)中,curl --json '{"key":"value"}' URL 是最简短的正确形式 — 它发送请求正文并将 Content-TypeAccept 头都设置为 application/json。在旧版 curl 中,使用 curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' URL

问:为什么我的 JSON API 说正文缺失或无效,即使我已经发送了?

两种常见原因。要么是您发送了 -d 但没有 Content-Type: application/json 头,因此服务器将其视为表单数据 — 添加头或使用 --json。要么是您的 shell 扰乱了 JSON,因为它被双引号包裹;使用单引号包裹负载,或者将其移入文件并使用 @file 发送。

问:-d--data-binary--json 之间有什么区别?

-d--data)发送正文,对于 @file,会去掉换行;它本身不设置 JSON 头。--data-binary 按照给定的内容精确发送正文,包括换行。--json 按原样发送正文 Content-TypeAccept 设置为 application/json;需要 curl 7.82.0 及以上版本。

问:如何发送 JSON 文件而不是内联文本?

在路径前加 @curl --json @body.json URL,或 curl -H "Content-Type: application/json" --data-binary @body.json URL。在字节必须完全与文件匹配的情况下,优先使用 --json @file--data-binary @file,因为 -d @file 会去掉换行。

问:如何在 Windows 上使用 curl 发送 JSON?

cmd.exe 不支持单引号,因此最简单可靠的方式是将 JSON 存放在文件中并使用 @body.json 发送。如果必须内联,使用反斜杠转义每个内部双引号。在 PowerShell 中,显式调用 curl.exe,以免触发 Invoke-WebRequest 别名,并仍然优先使用 @file 形式。
问:如果我使用 --json,我需要设置 Content-Type 头吗?

不需要。--json 会自动设置 Content-Type: application/json,以及 Accept: application/json。您只需添加一个显式头部来覆盖其中一个—例如一个不同的 Accept — 在这种情况下,将 -H 放在 --json 之后,以使其优先。


准备好构建您的 AI 驱动数据管道了吗?

加入我们的社区,获取免费的计划,并与正在构建基于 JSON 数据收集管道的开发者连接:Discord · Telegram

Scrapeless 注册以获取免费的爬虫浏览器运行时和住宅代理访问,并将您原型设计的 curl 请求转变为生产数据管道。


在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。

最受欢迎的文章

目录