在终端发送JSON HTTP请求主体
1. 概述
对 POST、PUT 和 PATCH 等动词的 HTTP 请求可以选择发送请求正文有效负载作为请求的一部分。这些数据可以是键值对的格式,也可以是JSON 和XML 等其他序列化格式。但是,有时不清楚我们如何发送请求正文并让服务器将其解析为 JSON 对象。
在本教程中,我们将学习如何借助Content-Type HTTP 标头正确地将 JSON 对象作为请求正文发送。
2. Linux 命令行 HTTP 客户端
在 Linux 中, curl 和 wget 是常见的基于终端的 HTTP 客户端。鉴于它在 Linux 生态系统中的流行,我们将在本文中使用它们进行演示。
要获取curl和wget,我们可以使用包管理器安装它们。例如,在 Ubuntu Linux 中,我们可以运行apt-get install来获取这些程序:
$ apt-get install curl
$ apt-get install wget
3.HTTPBin
HTTPBin 是一个免费的在线 HTTP 回显服务。它本质上接受 HTTP 请求并在响应中回显请求。该服务对于调试和检查我们的 HTTP 请求很有用。
例如,我们可以使用 POST HTTP 动词向 /post端点发送请求,并查看服务器在我们的请求中看到的内容:
$ curl -X POST https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-624a70cb-2818fca21d9d71f86fe110d3"
},
"json": null,
"origin": "",
"url": "https://httpbin.org/post"
}
现在,如果我们添加一个自定义标题X-Blogdemo-Title,我们将看到它反映在响应的 headers字段中:
$ curl -X POST -H "X-Blogdemo-Type: linux-article" https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-624a7118-3902adc8559ae0385170b8fa",
"X-Blogdemo-Type": "linux-article"
},
"json": null,
"origin": "",
"url": "https://httpbin.org/post"
}
在本文中,我们将向 HTTPBin发送请求,以便我们可以检查服务器所看到的实际请求。
4. HTTP 请求体及其类型
请求正文可以有多种格式用于不同的目的。例如,一个简单的 Web 表单将请求正文作为键值对传递给服务器。另一方面,更复杂的数据结构可能需要在请求正文中使用 JSON 或 XML 表示。
为了正确解析和解释请求正文,服务器依赖于请求中的Content-Type标头。本质上,**Content -Type标头指定了一个MIME 类型 ,告诉服务器请求正文中的数据类型。**例如,使用application/json MIME 类型告诉服务器请求正文是有效的 JSON 对象。常用的 MIME 类型列表,我们可以参考MDN 文档 。
5. 发送 JSON 数据
让服务器将请求正文正确解释为 JSON 的关键是适当地设置Content-Type请求标头。
5.1. 常见的陷阱
**在将 JSON 作为有效负载发送时,我们最常犯的错误之一是未指定请求正文的 MIME 类型。**大多数 HTTP 客户端(例如curl和 wget )默认为任何请求正文的*application/x-www-form-urlencoded MIME 类型。*如果端点需要一个格式正确的 JSON 对象,它会导致经常出现神秘的错误消息。
让我们看看默认行为:
$ curl -X POST -d '{"test": "data"}' https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"test\": \"data\"}": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "16",
"Content-Type": "application/x-www-form-urlencoded"
}
}
从响应中,我们可以看到curl传递了 header Content-Type: application/x-www-form-urlencoded。这导致服务器将我们传入的请求正文作为键值对处理。我们可以使用wget观察到相同的行为 :
$ wget -q -O- --post-data '{"test": "data"}' https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {
"{\"test\": \"data\"}": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "16",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org"
}
}
5.1. 使用curl发送 JSON
要使用curl发送 JSON 数据,我们使用*-d指定 JSON 有效负载的字符串表示。*此外,使用-H选项传入标头Content-Type: application/json也很重要**:
$ curl -X POST "https://httpbin.org/post" -d '{"site": "blogdemo", "articleId": 100, "author": {"name": "alice", "id": 1}}' -H "content-type: application/json"
{
"args": {},
"data": "{\"site\": \"blogdemo\", \"articleId\": 100, \"author\": {\"name\": \"alice\", \"id\": 1}}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "76",
"Content-Type": "application/json",
"Host": "httpbin.org"
},
"json": {
"articleId": 100,
"author": {
"id": 1,
"name": "alice"
},
"site": "blogdemo"
}
}
从响应中,我们可以看到服务器正确地将我们的数据解释为 JSON 并相应地解析它。
5.2. 使用wget发送 JSON
*使用wget ,我们使用–post-data参数指定 JSON 有效负载的字符串表示。*然后,我们使用–header参数指定application/json MIME 类型:
$ wget -q -O- --post-data '{"site": "blogdemo", "articleId": 100, "author": {"name": "alice", "id": 1}}' -H "https://httpbin.org/post" --header "content-type: application/json"
除此之外,我们可以使用*–post-file来读取文件的内容并使用wget将其作为请求体发送。例如,我们可以 使用–post-file参数将article_payload.json*的内容发送到服务器 :
$ wget -q -O- --post-file ./article_payload.json -H "https://httpbin.org/post" --header "content-type: application/json"
{
"args": {},
"data": "{\n \"site\": \"blogdemo\", \n \"articleId\": 100, \n \"author\": {\n\t\"name\": \"alice\", \n\t\"id\": 1\n }\n}\n",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "identity",
"Content-Length": "102",
"Content-Type": "application/json",
"Host": "httpbin.org"
},
"json": {
"articleId": 100,
"author": {
"id": 1,
"name": "alice"
},
"site": "blogdemo"
}
}