1 Post请求

POST 请求是一种常见的数据请求方式,相对于 GET 请求更安全、更灵活。一个标准的 POST 请求由以下三个部分组成:

  1. 请求行:包含了请求方法、URL 和 HTTP 协议版本。
  2. 请求头:包含了关于请求的附加信息,常见的请求头字段有 Content-TypeAuthorization
  3. 请求主体:请求的数据存储在请求主体中,具体的数据格式和编码方式由 Content-Type 字段确定。服务端会根据 Content-Type 字段使用不同的方式对请求体进行解析。

2 Post请求中的Content-Type

2.1 application/x-www-form-urlencoded

application/x-www-form-urlencoded是POST请求中最常见的一种编码方式,适用于表单数据提交。它是原生表单 POST 提交(enctype)的默认值,大部分服务端语言都对这种方式有很好的支持。

当使用 application/x-www-form-urlencoded 提交数据时,需要对参数进行 urlencoded 编码和序列化。数据被编码成以 & 分隔的键值对,同时以 = 分隔键和值,非字母或数字的字符会被 percent-encoding(百分比编码)。

例如,表单提交参数为:

param1:website,
param2:https://www.google.com

经过 urlencoded 编码后:

param1:website
param2:https%3A%2F%2Fwww.google.com

再经过序列化,得到结果:

param1=website&param2=https%3A%2F%2Fwww.google.com

采用这种格式发送到服务器的 HTTP 消息的主体本质上是一个巨大的查询字符串,结构简单。

但是由于需要对数据进行编码,这意味着值中存在的每个非字母数字,将需要三个字节来表示它。对于大型二进制文件,请求体将增加三倍,非常低效。

另外由于对数据进行了编码,非 ASCII 码的数据会丢失,所以类似传文件的场景也不能使用这种方式。

适用场景:数据量小的简单数据。

2.2 multipart/form-data

这种编码方式主要用于文件上传,可以有效地传输二进制(非字母数字)数据,同时还可以携带其他信息。

multipart/form-data 格式中,数据被划分为多个部分(part),每个部分都以一个标头(headers)开始,并使用一组空行来分隔。同时,每个部分还包含一个唯一的 boundary 字符串,用于标识不同部分之间的边界。

每个部分包含以下组成:

  • 边界:--boundary
  • 标头:元数据,如 Content-TypeContent-Disposition
  • 空行:用于分隔标头和正文数据
  • 正文数据:包含实际的文件数据或表单字段的值

最后以 --boundary-- 表示请求体结束。

一个简单的例子如下:

POST http://www.example.com/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123

------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="username"

zhang san
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="avatar"; filename="avatar.png"
Content-Type: image/png

...二进制数据...
------WebKitFormBoundaryABC123--

在这个例子中,请求头中指定了 Content-Type: multipart/form-data,并设置了一个唯一的 boundary 字符串作为分隔符(在此例中为 ----WebKitFormBoundaryABC123)。

在请求体中,我们可以看到两个部分

  • 第一部分:以 --boundary 开始,并包含了一个标头 Content-Disposition: form-data; name="username"。这表示这个部分是一个表单字段,字段名为 username,字段值为 zhang san

  • 第二部分:以 --boundary 开始,并包含了两个标头。首先是 Content-Disposition: form-data; name="avatar"; filename="avatar.png"。然后是 Content-Type: image/png,指定了这个部分的数据类型为 image/png。接着是二进制文件数据主体

  • 最后以 --boundary-- 表示结束

    multipart/form-data 也可以用于传递普通数据,但是由于每个字段都有自己的一组 MIME 标头和边界字符串,这会增加数据包的大小。相对于其他简单的编码方式(如 application/x-www-form-urlencoded),它在处理普通数据时效率低,开销更大。

适用场景:文件上传、带有二进制数据的请求。

2.3 application/json

使用 application/json 编码方式,可以将数据序列化成一个 JSON 字符串作为请求主体。相比其他只能传输键值对的方式,这种编码方式更加灵活和简单高效。它支持复杂的嵌套结构、数组、对象等,非常适合传输包含多层级数据关系的数据。

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{"name":"test", "age": 24, "hobby":["a","b","c"]}

适用场景:复杂的结构化的数据。

参考