使用post请求发送数据时候,数据会放在body部分而不是头信息中,而数据放在body中传输时候,我们可以将这个body中的信息看作是一个长长的单个字符串,而我们使用不同的编码就是将这个数据用不同的形式进行发送。
application/x-www-form-urlencoded
原理
它是post的默认格式,它默认使用了一些特殊的符号作为分割符,例如&(ascii码为0x26)
, =(0x3D)
, (空格)等,我们input中的name、value信息会发送时使用=
连接,不同的input之间使用&
连接;在接收端使用相同方式进行解码,一旦遇到&
,=
等字符将会按照规定将这个长字节断开,还原为原来key:value 形式的数据,以供我们使用。所以使用这种格式解码时,可以看作是一个个字节进行扫描的,并使用特殊的字节将其不同的部分区分。
问题
这种方式发送一个非特殊字符的单字节字符时没有问题的,当我们需要发送一个多字节字符,例如中文的中
字,如果直接使用utf-8编码发送,其编码为0xE4B8AD
,会使用三个字节传输,分别为0xE4
,0xB8
,0xAD
,当某些中文或者多字节的字符发送时,恰好有一个字节解码为0x26
或者0x3D
时,这个多字节字符中一个字节将会被接收段解码为=
或&
符号这中特殊字节,从而将数据从此处断开,产生数据的错误。
为了解决这个问题,使用了JS中URLencode转码方法,也就是URL编码,我们经常看到一个URL类似于https://cn.bing.com/search?q=ascii%E7%A0%81%E8%A1%A8
, %E7%A0%81%E8%A1%A8
就是经过这种编码方式产生的。我们发送上面的中
,utf-8编码为0xE4B8AD
(这是3个字节的16进制表示法,它表示的字符是中
一个字符),不能直接进行发送。需要使用URLencode进行转码,使用这个编码的16进制形式的字符串为基础,每两个字符前添加一个%,得到字符串%E4%B8%AD
(这是一个字符串,每一个字符都是一个字节,这里总共9个字节),再将这个字节发送。这样就解决了上面的问题。
使用这中方式发送的数据,一个中文将会被编码为9个字节进行发送,在发送大量的中文及多字符数据时会严重的浪费网络带宽资源,一般在发送少量的数据使用。例如下面是在一个表单中发送{country: 中国, city:北京}信息时候,浏览器发送的部分信息
POST /users/ HTTP/1.1
Host: localhost:8000
Content-Type: application/x-www-form-urlencoded // 头中指定格式
country=%E4%B8%AD%E5%9B%BD&city=%E5%8C%97%E4%BA%AC // 编码后的数据
form-data
application/x-www-form-urlencoded
必须进行多字节字符的编码,这是由于多字节字符的单个字节信息可能与特殊字节信息冲突。而form-data的解决方法就是, 不在使用这些单个字节的特殊字符作为特殊分割,而是告诉对方使用分割字符串。上面的{country: 中国, city:北京}表单信息使用这种格式发送时,浏览器发送的数据为。
POST /users/ HTTP/1.1
Host: localhost:8000
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW--,
Content-Disposition: form-data; name="country"
中国
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="city"
北京
------WebKitFormBoundary7MA4YWxkTrZu0gW--
HASKELL 全屏
在header头信息中,Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
分别指定了格式和 boundary(分割字符串),在body中使用了这个boundary指定的字符串作为分割,从而可以轻易的还原为key:value的形式。这里的中国
和北京
中,每一个字符l例如中
,都是直接使用utf-8编码(大部分网络传输都使用该编码)后进行传输的,也就是说每个中文只需要3个字节。
总结
application/x-www-form-urlencoded 他能简洁的将key:value的数据进行分割。这一点相比form-data使用长长的字符串作为分割符优势巨大,虽然对于多字节的数据会因为编码造成字节量剧增(可以看到一个中文字符增加了2倍字节量),但是在单字节或者是少量的数据时,这种方式是划算的。
form-data 是一种重视数据的方式,通常我们在value值中会发送大量的文本信息,或者直接的传送一个文件,数据直接编码为二进制发送,不会产生多余的字节,适合大文本的传输。
1)application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
<form action="form_action.asp" enctype="text/plain">
<p>First name: <input type="text" name="fname" /></p>
<p>Last name: <input type="text" name="lname" /></p>
<input type="submit" value="Submit" />
</form>
此时可以看到,
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式很好的支持,常用的如jQuery中的ajax请求,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8
(2)multipart/form-data
这也是常见的post请求方式,一般用来上传文件,各大服务器的支持也比较好。所以我们使用表单 上传文件 时,必须让<form>表单的enctype属性值为 multipart/form-data.
注意:以上两种方式:application/x-www-form-urlencoded和multipart/form-data都是浏览器原生支持的。
(3)application/json
application/json作为响应头并不陌生,实际上,现在很多时候也把它作为请求头,用来告诉服务端消息主体是序列化的JSON字符串,除了低版本的IE,基本都支持。除了低版本的IE都支持JSON.stringify()的方法,服务端也有处理JSON的函数,使用json不会有任何麻烦。例如:
//请求数据
var data = {name:'jack',sex:'man'};
//请求数据序列化处理
JSON.stingify(data);
//结果:{'name':'jack','sex':'man'};
二、postman的几种参数格式
form-data、x-www-form-urlencoded、raw、binary的区别
1.form-data对应的是页以form表单提交传值的情形
等价于http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件
POST HTTP/1.1
Host: test.app.com
Cache-Control: no-cache
Postman-Token: 59227787-c438-361d-fbe1-75feeb78047e
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="filekey"; filename=""
Content-Type:
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="textkey"
tttttt
------WebKitFormBoundary7MA4YWxkTrZu0gW--
请求体中的boundary参数指定的就是分隔体,可以看到请求内容被分为了两段,第一段对应filekey,第二段对应textkey。
2. x-www-form-urlencoded
即application/x-www-from-urlencoded,将表单内的数据转换为Key-Value。
POST HTTP/1.1
Host: test.app.com
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: e00dbaf5-15e8-3667-6fc5-48ee3cc89758
key1=value1&key2=value2
form-data与x-www-form-urlencoded的区别
- multipart/form-data:可以上传文件或者键值对,最后都会转化为一条消息
- x-www-form-urlencoded:只能上传键值对,而且键值对都是通过&间隔分开的
3.raw对应的是入参是任意格式的可以上传任意格式的【文本】,可以上传text、json、xml、html等
(4)binary
相当于Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件,但是一次只能上传一个文件