前言
我们需要清楚http是什么
http是web文档的传输协议,协议有很多种,还包括ip
, ftp
, dns
, tcp
等等,这些协议统称为tcp/ip
协议族
tcp/ip
协议族是分层管理的,即应用层
,传输层
,网络层
, 链路层
例如,当一个请求发出时,简单的来说:
- 由应用层的http协议对请求进行处理(通过dns协议解析域名得到ip地址)。此时请求的数据为何种格式?
- http协议将数据整理成报文格式,然后将报文以
流
的形式传递给下层tcp
- http协议将数据整理成报文格式,然后将报文以
- 由传输层的tcp(传输控制协议)等协议来规定如何进行传输。此时请求的数据为何种格式?
- tcp将“报文流”分段,分装到ip分组中
- 请求的数据格式被转化为
数据包
,网络层来规定数据包
以何种路径进行传输- 在网络层,通过ip协议来得到传输路线。ip协议有2个重要条件
ip地址
和mac地址
- 在网络层,通过ip协议来得到传输路线。ip协议有2个重要条件
- 链路层即用来处理连接网络的硬件部分,比如网卡等
我们此刻需要讨论的get与post,是属于应用层的http协议内容。与其它无关。
get与post的区别
首先,这个问题是有歧义的。
宽泛的说,它们都是基于tcp/ip
协议族的,当然这句话说的没有任何意义,就像在放屁一样。
实际上,get与post只是http协议中定义的一种method,为约定俗成的针对某种情况下使用某种特定的方法,并没有严格意义上的不同。所以讲区别,只是说在使用上的一些区别与优劣。
就像html标签一样拥有特定的语义,在语义上的区别:
- get更适合去获取由请求URI所指定资源的信息
- post的具体功能由服务器来决定,我们一般用用实体信息扩展数据库
使用上的区别
- get的请求参数是放在url上的,而post是放在
request body
即报文的请求主体中。
但是http协议并没有规定必须这么做,这种做法只是一种规范,就跟es6
中规定的const 与 let
一样,你非得把一个不会变更的变量用let
声明那也是没问题的。 - 参数的长度限制,http协议也明确指出HTTP头和Body都没有长度的要求
但由于规范,get的参数都是拼在url上的,url长度会被浏览器限制;另外,过长的url也会给服务器的解析造成负担。
有说现代浏览器最大url长度为90kb的,在utf-8编码中,一个英文字母占据一个字节,一个中文占据3个字节;在ASCII码中,一个英文字母占据一个字节,一个中文占据2个字节; - get上的参数默认会以
application/x-www-form-urlencoded
格式,空格字符会被转化为+
,非数字字母字符会被转化为%HH
,即一个%和2个16进制的数字表示的ascii码
当然也可以是二进制或其它格式,但是效率会很低The content type “application/x-www-form-urlencoded” is inefficient for sending large quantities of binary data or text containing non-ASCII characters
- post的请求实体主体部分
- 由于get是以url的形式请求响应的某种资源,它是可被缓存的;而post
以上有感于GET和POST有什么区别?及为什么网上的多数答案都是错的
http://man.chinaunix.net/develop/rfc/RFC1945.txt (方法定义(Method Definitions))
什么是request body
http报文分为请求报文和响应报文,结构基本一致。
请求报文格式如下
// 起始行 <method> <request-url> <version>
GET /images/test.jpg HTTP/1.1
// 首部 <headers>
Content-Type: application/x-www.form-urlencoded
// 实体 <entity-body>
name=ym&age=18
响应报文只有起始行不同
// <version> <status> <reason-phrase>
HTTP/1.1 200 OK
这里的request body便是请求实体主体entity-body
实体分为实体首部和实体主体,我们可以把“报文看作是箱子,实体看作是货物”
request body中的MIME类型
MIME类型即媒体类型,是一种标准,针对文件的。所以讲request body中的MIME类型,是指当Content-Type
为multipart/form-data
并添加了文件时才有的类型值。
MIME类型是标准化的名字,用以说明作为货物运载实体的基本媒体类型,客户端应用程序使用MIME类型来解释和处理其内容
MIME类型组成 主类型/子类型
,常见的如下
text/html
application/vnd.ms-powerpoint
image/png
在Content-Type
为multipart/form-data
时,实体的主体由多部分组成,每一部分的Content-Type
默认为text/plain
,举个例子
<FORM action="http://server.com/cgi/handle"
enctype="multipart/form-data"
method="post">
<INPUT type="text" name="submit-name">
<INPUT type="file" name="files">
</FORM>
点击提交后的实体主体(文件多选)
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-Disposition: file; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
input选择多个文件后,也就是批量上传,Content-Type就为multipart/mixed,相当于在Content-Type为multipart/form-data嵌入了Content-Type为multipart/mixed的部分。
If multiple files are to be returned as the result of a single form entry, they should be returned as “multipart/mixed” embedded within the “multipart/form-data”.
Content-Type
还支持传递字符编码类型
Content-Type: application/x-www-form-urlencoded; charset=utf-8
规范的来讲不同的Content-Type应该使用不同的数据类型,例如
- application/x-www-form-urlencoded 实体主体只能是一个字符串
- multipart/form-data 实体的主体应该包含多部分,例如文件,二进制流或非acsll码的数据,contain files, non-ASCII data, and binary data
但是这不是绝对的,规范如下
The content type “application/x-www-form-urlencoded” is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type “multipart/form-data” should be used for submitting forms that contain files, non-ASCII data, and binary data.
只是说效率会很低,是不建议这么做,并非不能。
https://www.w3.org/TR/REC-html40/interact/forms.html#form-data-set
什么是enctype
enctype是form表单的一个属性,用来指定http报文的编码方式,最终对应的也是上面说的Content-Type
http传递复杂数据类型的几种方式
对于简单数组 { key: [1, 2, 3] }
来说
- application/x-www-form-urlencoded,用qs的
arrayFormat
选项来说,有3种情况- brackets 形如
key[]=1&key[]=2&key[]=3
- repeat 形如
key=1&key=2&key=3
- indices 形如
key[0]=1&key[1]=2&key[2]=3
- brackets 形如
具体使用哪种,需要与后端对接清楚。
它们的本质,都是拼接而来的字符串,我们知道,对于application/x-www-form-urlencoded
,除了字母数字与+号,其余的都会转成ascll码,那对于嵌套的数据使用qs也是可以去做转化。但其实更适合用application/json
,因为调试更清晰吧。
https://borninsummer.com/2015/10/27/about-using-json-in-http-body/