Contents

在终端发送JSON HTTP请求主体

1. 概述

对 POST、PUT 和 PATCH 等动词的 HTTP 请求可以选择发送请求正文有效负载作为请求的一部分。这些数据可以是键值对的格式,也可以是JSON  和XML 等其他序列化格式。但是,有时不清楚我们如何发送请求正文并让服务器将其解析为 JSON 对象。

在本教程中,我们将学习如何借助Content-Type HTTP 标头正确地将 JSON 对象作为请求正文发送。

2. Linux 命令行 HTTP 客户端

在 Linux 中,  curl  和 wget 是常见的基于终端的 HTTP 客户端。鉴于它在 Linux 生态系统中的流行,我们将在本文中使用它们进行演示。

要获取curlwget,我们可以使用包管理器安装它们。例如,在 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"
  }
}