JSON 数据与 curl POST 请求:完整教程
在现代 Web 开发和 API 交互中,JSON (JavaScript Object Notation) 已成为数据交换的事实标准。它轻量、易于人类阅读和编写,同时也易于机器解析和生成。curl
是一个强大的命令行工具,用于传输数据,支持多种协议,包括 HTTP 和 HTTPS。将这两者结合起来——使用 curl
发送包含 JSON 数据的 POST 请求——是与 Web API 交互、测试服务端点或自动化任务的基础技能。
本教程将深入探讨 JSON 的基础知识、curl
的 POST 请求机制,并详细说明如何将它们结合起来,发送带有 JSON 载荷(payload)的 POST 请求。我们将涵盖基础概念、多种方法、实际示例、常见问题及最佳实践。
目录
- 理解 JSON (JavaScript Object Notation)
- 什么是 JSON?
- JSON 的优势
- JSON 的基本结构(对象和数组)
- JSON 数据类型
- JSON 语法规则
- JSON 验证
- 理解
curl
和 HTTP POST 请求curl
简介- HTTP 请求方法:POST 的作用
- 为什么使用 POST 发送数据?
- 使用
curl
发送 POST 请求(基础)-X POST
选项-d
或--data
选项:发送表单数据
- 使用
curl
发送 JSON 数据的 POST 请求- 关键要素:
Content-Type
标头 - 方法一:使用
-d
或--data
发送内联 JSON 字符串 - 方法二:使用
-d @
或--data @
从文件读取 JSON 数据 - 方法三:使用
--data-raw
(推荐) - 方法四:结合
echo
或printf
与管道 - 设置正确的
Content-Type
标头 (-H
)
- 关键要素:
- 实际示例
- 示例 1:向测试 API 发送简单的 JSON 对象
- 示例 2:发送包含数组和嵌套对象的复杂 JSON
- 示例 3:从文件读取 JSON 数据发送
- 处理响应
- 查看响应状态码和标头 (
-i
,-v
) - 保存响应体到文件 (
-o
) - 结合
jq
处理 JSON 响应
- 查看响应状态码和标头 (
- 身份验证与
curl
POST- 基本认证 (
-u
) - Bearer Token (
-H "Authorization: Bearer ..."
)
- 基本认证 (
- 常见问题与故障排除
- 错误:服务器返回 400 Bad Request (通常是 JSON 格式问题)
- 错误:服务器返回 415 Unsupported Media Type (通常是
Content-Type
问题) - JSON 字符串中的引号问题
- Shell 特殊字符转义
- 最佳实践
- 始终设置
Content-Type: application/json
- 验证你的 JSON 数据
- 使用文件存储复杂的 JSON
- 注意 Shell 转义
- 利用
-v
进行调试
- 始终设置
- 总结
1. 理解 JSON (JavaScript Object Notation)
什么是 JSON?
JSON 是一种轻量级的数据交换格式。它源于 JavaScript 的一个子集,但如今已成为一种语言无关的格式。Web API(尤其是 RESTful API)广泛使用 JSON 来发送和接收数据。
JSON 的优势
- 可读性强:JSON 结构清晰,易于人类阅读和理解。
- 易于解析:各种编程语言都有成熟的库可以轻松解析和生成 JSON。
- 轻量级:相比 XML 等其他格式,JSON 语法更简洁,冗余信息少,传输效率更高。
- 广泛支持:几乎所有的现代编程语言和平台都原生或通过库支持 JSON。
JSON 的基本结构
JSON 基于两种结构:
- 对象 (Object):由花括号
{}
包裹的无序键值对(key-value pair)集合。键(key)必须是字符串(用双引号包裹),值(value)可以是任何有效的 JSON 数据类型。键值对之间用逗号,
分隔。
json
{
"name": "Alice",
"age": 30,
"isStudent": false
} - 数组 (Array):由方括号
[]
包裹的有序值(value)列表。值之间用逗号,
分隔。数组中的值可以是不同的 JSON 数据类型。
json
[
"apple",
"banana",
"cherry",
123,
true
]
这两种结构可以相互嵌套,构成复杂的数据模型。
JSON 数据类型
JSON 支持以下基本数据类型:
- 字符串 (String):必须用双引号
""
包裹。 - 数值 (Number):整数或浮点数,不使用引号。
- 布尔值 (Boolean):
true
或false
(小写,不使用引号)。 - null:表示空值 (小写,不使用引号)。
- 对象 (Object):见上文。
- 数组 (Array):见上文。
JSON 语法规则
- 对象使用花括号
{}
。 - 数组使用方括号
[]
。 - 键值对格式为
"key": value
。键必须是双引号字符串。 - 键值对或数组元素之间用逗号
,
分隔。最后一个元素后面不能有逗号(部分解析器允许,但标准不允许)。 - 字符串必须用双引号
""
包裹。单引号无效。 - 特殊字符(如双引号、反斜杠)在字符串中需要用反斜杠
\
转义(例如\"
,\\
)。
JSON 验证
发送格式错误的 JSON 是导致 API 请求失败的常见原因。在发送请求之前,最好验证 JSON 数据的有效性。可以使用在线 JSON 验证器(如 JSONLint)或命令行工具(如 jq
)来检查。
“`bash
使用 jq 验证 (如果无效会报错)
echo ‘{“name”: “Alice”, “age”: 30,}’ | jq .
输出错误: parse error: Expected value before ‘}’ at line 1, column 28
“`
2. 理解 curl
和 HTTP POST 请求
curl
简介
curl
(发音 “curl”) 是一个功能强大的命令行工具和库,用于通过 URL 语法传输数据。它支持包括 HTTP, HTTPS, FTP, FTPS, SCP, SFTP, LDAP, SMB 等多种协议。在 Web 开发中,curl
常用于测试 API 端点、下载文件、发送请求等。
HTTP 请求方法:POST 的作用
HTTP 定义了多种请求方法(也称谓词),用于指示对目标资源执行的操作。常见的有 GET, POST, PUT, DELETE 等。
- GET:通常用于请求获取资源信息,数据一般通过 URL 参数传递。幂等(多次请求结果相同)。
- POST:通常用于向服务器提交数据,导致资源状态的改变或创建新资源。数据通常包含在请求体(request body)中。非幂等。
为什么使用 POST 发送数据?
- 创建或更新资源:POST 常用于创建新资源(如注册新用户、发布新文章)或更新现有资源。
- 发送大量数据:GET 请求通过 URL 传递数据,URL 长度有限制。POST 请求将数据放在请求体中,可以发送更大量的数据。
- 发送敏感数据:虽然 POST 本身不加密(需要 HTTPS),但请求体中的数据不会像 URL 参数那样直接暴露在浏览器历史、服务器日志(可能配置不记录 body)或网络嗅探中那么明显。
- 非幂等操作:对于会改变服务器状态且多次执行结果不同的操作(如下单),通常使用 POST。
3. 使用 curl
发送 POST 请求(基础)
在深入 JSON 之前,先看看 curl
发送基本 POST 请求的方式。
-X POST
选项
curl
默认发送 GET 请求。要显式指定 POST 方法,使用 -X POST
选项:
bash
curl -X POST https://httpbin.org/post
-d
或 --data
选项:发送表单数据
-d
选项用于发送 HTTP POST 请求的数据。默认情况下,curl
会将使用 -d
提供的数据视为 application/x-www-form-urlencoded
类型的数据,就像 HTML 表单提交一样。
“`bash
发送 key1=value1&key2=value2 格式的数据
curl -X POST -d “name=Alice&city=Wonderland” https://httpbin.org/post
“`
curl
会自动设置 Content-Type
为 application/x-www-form-urlencoded
。
4. 使用 curl
发送 JSON 数据的 POST 请求
现在,我们将重点放在如何使用 curl
发送 JSON 数据。关键在于两点:
- 提供 JSON 数据:通过
-d
或相关选项将 JSON 字符串作为请求体发送。 - 设置
Content-Type
标头:明确告诉服务器请求体中的数据是 JSON 格式。
关键要素:Content-Type
标头
为了让服务器正确解析请求体中的 JSON 数据,必须设置 HTTP Content-Type
请求标头为 application/json
。这通过 curl
的 -H
或 --header
选项完成。
bash
-H "Content-Type: application/json"
方法一:使用 -d
或 --data
发送内联 JSON 字符串
可以直接在命令行中将 JSON 字符串传递给 -d
选项。
bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"username": "testuser", "email": "[email protected]"}' \
https://api.example.com/users
注意事项:
- 引号:JSON 字符串本身需要双引号。为了在 Shell 中正确传递这个包含双引号的字符串,通常将整个 JSON 字符串用单引号
' '
包裹起来。如果 JSON 字符串内部需要包含单引号(虽然不常见,但在字符串值中可能出现),则需要更复杂的转义或使用其他方法。 - Shell 转义:如果 JSON 字符串中包含 Shell 的特殊字符(如
!
,$
,&
等),并且你使用了双引号""
包裹 JSON 字符串,那么这些特殊字符可能需要转义。使用单引号' '
包裹可以避免大部分 Shell 变量展开和特殊字符解释。
方法二:使用 -d @
或 --data @
从文件读取 JSON 数据
当 JSON 数据比较复杂或较长时,将其放在一个单独的文件中是更好的选择。可以使用 @
符号告诉 curl
从文件中读取数据。
假设有一个名为 data.json
的文件,内容如下:
json
{
"product": "Laptop",
"quantity": 1,
"price": 1200.50,
"features": ["16GB RAM", "512GB SSD", " backlit keyboard"]
}
可以使用以下命令发送:
bash
curl -X POST \
-H "Content-Type: application/json" \
-d @data.json \
https://api.example.com/orders
@
后面紧跟文件名。curl
会读取 data.json
的全部内容作为请求体。这是处理复杂 JSON 的推荐方法。
方法三:使用 --data-raw
(推荐)
--data-raw
选项与 -d
类似,但它有一个关键区别:它不会对数据进行任何特殊处理。特别是,如果数据以 @
开头,--data-raw
会将其视为字面量 @
字符,而不是文件读取指令。这在需要发送以 @
开头的 JSON 字符串时很有用。
对于发送 JSON 而言,--data-raw
通常与 -d
行为一致(因为 JSON 字符串通常不以 @
开头),但有时被认为更明确,因为它避免了 -d
可能进行的 URL 编码(虽然在 Content-Type: application/json
时 -d
通常也不会进行 URL 编码)。
bash
curl -X POST \
-H "Content-Type: application/json" \
--data-raw '{"message": "@channel Alert!"}' \
https://api.example.com/notify
使用 --data-raw @filename
仍然可以从文件读取,行为与 -d @filename
相同。
bash
curl -X POST \
-H "Content-Type: application/json" \
--data-raw @data.json \
https://api.example.com/orders
方法四:结合 echo
或 printf
与管道
虽然不常用,但也可以使用 echo
或 printf
生成 JSON 字符串,并通过管道 |
传递给 curl
,使用 -d @-
从标准输入读取。
bash
echo '{"key": "value"}' | curl -X POST -H "Content-Type: application/json" -d @- https://api.example.com/endpoint
或者使用 printf
(通常更安全,因为它不会解释反斜杠序列):
bash
printf '%s' '{"key": "value", "path": "/usr/local"}' | curl -X POST -H "Content-Type: application/json" -d @- https://api.example.com/endpoint
这种方法在脚本中动态生成 JSON 时可能有用,但对于静态 JSON,文件或内联字符串通常更清晰。
设置正确的 Content-Type
标头 (-H
)
再次强调:无论使用哪种 -d
相关的方法提供 JSON 数据,都必须使用 -H "Content-Type: application/json"
来设置正确的标头。否则,服务器可能无法理解你发送的数据格式,导致请求失败(常见错误是 415 Unsupported Media Type)。
“`bash
正确示例
curl -X POST -H “Content-Type: application/json” -d ‘{“data”: 123}’ https://httpbin.org/post
错误示例 (缺少 Content-Type) – 服务器可能按默认处理或报错
curl -X POST -d ‘{“data”: 123}’ https://httpbin.org/post
“`
5. 实际示例
我们将使用 https://httpbin.org
作为测试目标,它是一个非常有用的服务,可以回显你的请求信息。
示例 1:向测试 API 发送简单的 JSON 对象
bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "Bob", "role": "developer"}' \
https://httpbin.org/post
预期响应 (部分):
json
{
// ... (其他信息)
"data": "{\"name\": \"Bob\", \"role\": \"developer\"}",
"headers": {
"Accept": "*/*",
"Content-Length": "38",
"Content-Type": "application/json", // <--- 确认 Content-Type 正确
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=..."
},
"json": { // <--- httpbin 会尝试解析 JSON 并放在这里
"name": "Bob",
"role": "developer"
},
"origin": "...",
"url": "https://httpbin.org/post"
}
注意响应中的 json
字段,httpbin.org
成功解析了我们发送的 JSON 数据。
示例 2:发送包含数组和嵌套对象的复杂 JSON
bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD12345",
"customer": {
"id": "CUST001",
"email": "[email protected]"
},
"items": [
{"sku": "ITEM01", "quantity": 2},
{"sku": "ITEM02", "quantity": 1}
],
"isPriority": true
}' \
https://httpbin.org/post
这个例子中,JSON 字符串跨越多行以提高可读性。在单引号 ' '
内部,换行符会被保留为字符串的一部分(虽然 JSON 标准会忽略值之间的空白符)。
示例 3:从文件读取 JSON 数据发送
创建文件 payload.json
:
json
{
"event": "user_signup",
"timestamp": "2023-10-27T10:30:00Z",
"details": {
"userId": "u-987xyz",
"source": "web_form"
}
}
执行命令:
bash
curl -X POST \
-H "Content-Type: application/json" \
-d @payload.json \
https://httpbin.org/post
这会读取 payload.json
的内容并将其作为请求体发送。
6. 处理响应
curl
不仅用于发送请求,也用于查看和处理服务器的响应。
查看响应状态码和标头 (-i
, -v
)
-i
(--include
):在输出中包含 HTTP 响应标头。
bash
curl -i -X POST -H "Content-Type: application/json" -d '{"ping": "pong"}' https://httpbin.org/post
你会先看到类似HTTP/1.1 200 OK
,Content-Type: application/json
等标头,然后才是响应体。-v
(--verbose
):提供更详细的输出,包括请求和响应标头,以及连接信息。非常适合调试。
bash
curl -v -X POST -H "Content-Type: application/json" -d '{"ping": "pong"}' https://httpbin.org/post
保存响应体到文件 (-o
)
使用 -o
(--output
) 选项可以将响应体保存到指定文件。
bash
curl -X POST \
-H "Content-Type: application/json" \
-d @payload.json \
https://api.example.com/process \
-o response.json
响应体内容将被写入 response.json
文件。
结合 jq
处理 JSON 响应
如果 API 返回 JSON 响应,可以使用 jq
(一个强大的命令行 JSON 处理器)来解析、过滤和格式化输出。
“`bash
仅提取响应中的 json.name 字段
curl -s -X POST \
-H “Content-Type: application/json” \
-d ‘{“name”: “Charlie”, “city”: “London”}’ \
https://httpbin.org/post | jq ‘.json.name’
输出: “Charlie”
“`
-s
选项 (--silent
) 用于抑制 curl
的进度条和错误信息,使输出更干净,适合管道处理。
7. 身份验证与 curl
POST
许多 API 需要身份验证。curl
支持多种认证机制。
基本认证 (-u
)
使用 -u username:password
或 --user username:password
。
bash
curl -X POST \
-H "Content-Type: application/json" \
-u myuser:mypassword \
-d '{"data": "secret"}' \
https://api.example.com/secure/resource
curl
会自动生成 Authorization: Basic <base64-encoded-credentials>
标头。
Bearer Token (-H "Authorization: Bearer ..."
)
这是 OAuth 2.0 和许多现代 API 常用的方式。直接使用 -H
添加 Authorization
标头。
“`bash
TOKEN=”your_actual_api_token_here”
curl -X POST \
-H “Content-Type: application/json” \
-H “Authorization: Bearer $TOKEN” \
-d @data.json \
https://api.example.com/protected/endpoint
“`
8. 常见问题与故障排除
错误:服务器返回 400 Bad Request
这通常意味着服务器无法理解你的请求。对于 JSON POST 请求,最常见的原因是:
- JSON 语法错误:多余的逗号、引号使用不当(单引号代替双引号)、括号不匹配等。仔细检查 JSON 结构,使用验证器。
- 数据内容不符合 API 预期:例如,缺少必需字段,数据类型错误(期望数字却发送了字符串)。查阅 API 文档。
错误:服务器返回 415 Unsupported Media Type
这几乎总是因为缺少 Content-Type: application/json
标头,或者标头值不正确。服务器明确表示它不支持你发送的数据格式(即使数据本身是有效的 JSON)。
解决方案:确保你的 curl
命令包含 -H "Content-Type: application/json"
。
JSON 字符串中的引号问题
JSON 标准要求键和字符串值都使用双引号 ""
。当在 Shell 中构造 curl
命令时,这会与 Shell 的引号规则冲突。
- 最佳实践:将整个 JSON 数据用单引号
' '
包裹。
bash
-d '{"key": "value with \"inner\" quotes"}'
在单引号内,双引号是普通字符。如果字符串值本身需要包含双引号,需要使用 JSON 的转义\"
。 - 如果必须用双引号包裹 (例如,需要 Shell 变量替换),则内部的双引号需要被 Shell 转义
\
:
bash
USER="dave"
# 注意内部 \"
-d "{\"username\": \"$USER\", \"message\": \"Hello \\\"World\\\"!\"}"
这很快变得难以阅读和维护。
Shell 特殊字符转义
如果 JSON 字符串(尤其是在使用双引号 ""
包裹时)包含 Shell 特殊字符(如 $
, !
, &
, *
, ?
, (
, )
等),它们可能会被 Shell 解释。使用单引号 ' '
包裹可以避免大多数这类问题。如果无法避免,请仔细转义。
9. 最佳实践
- 始终设置
Content-Type: application/json
:这是发送 JSON 数据时最重要的标头。 - 验证你的 JSON 数据:在发送前使用工具(如
jq
或在线验证器)检查 JSON 的有效性,避免 400 错误。 - 使用文件存储复杂的 JSON:对于长或复杂的 JSON 结构,使用
-d @filename
或--data-raw @filename
更清晰、更易于管理。 - 注意 Shell 引号和转义:优先使用单引号
' '
包裹内联 JSON 字符串,以减少 Shell 转义的复杂性。 - 利用
-v
进行调试:当请求失败或行为不符合预期时,-v
(--verbose
) 是你最好的朋友,它会显示详细的请求和响应信息,包括发送的标头和数据。 - 使用 HTTPS:对于生产环境和任何包含敏感数据的请求,始终使用 HTTPS URL。
- 查阅 API 文档:确保你发送的 JSON 结构和内容符合目标 API 的要求(必需字段、数据类型、格式等)。
10. 总结
掌握使用 curl
发送 JSON POST 请求是与现代 Web API 交互的基础技能。本教程详细介绍了 JSON 的基础、curl
发送 POST 请求的方法,并重点阐述了如何正确地将 JSON 数据作为请求体发送,特别是设置 Content-Type: application/json
标头的重要性。我们探讨了内联发送、从文件发送等多种方法,并提供了实际示例、处理响应的技巧、身份验证方法以及常见问题的解决方案。
通过理解这些概念和实践,你将能够更自信、更高效地使用 curl
与需要 JSON 数据的 API 进行交互,无论是进行测试、开发还是自动化工作流程。记住,仔细构造 JSON、正确设置标头,并利用 curl
的调试选项,是成功的关键。