GET和POST是HTTP协议最常用的两种请求方法。所以我们需要了解它们之间的区别,才能更好,更合适地使用它们。

目录

GET和POST的本质区别是它们的设计初衷

GET和POST在使用上的差异

触发请求的方式

如何携带请求数据?

携带的数据大小是否有限制,限制是多少?

请求参数是否可以被缓存?

请求参数的编码方式

请求参数的格式

GET和POST在安全性上的差异

对于服务器来说

对于浏览器来说

对于网络传输来说

GET和POST在性能上的差异


GET和POST的本质区别是它们的设计初衷

GET一般用于客户端向服务器 获取 和 检索 数据

POST 一般用于客户端向服务器 创建 或 更新 数据

GET和POST在使用上的差异

触发请求的方式

对于GET来说:

1、浏览器地址栏输入网址后回车,会触发GET请求

2、HTML文档中script标签,link标签,img标签引入外部文件时,会触发GET请求

3、通过点击a标签超链接跳转网页,会触发GET请求

4、通过form表单发起GET请求

5、通过ajax发起GET请求

对于POST来说:

1、通过form表单发起POST请求

2、通过ajax发起POST请求

如何携带请求数据?

对于GET来说:

既可以在URL携带,也可以在请求体中携带。但是,一般服务器端只会获取从URL中获取GET的请求参数。

对于POST来说:

既可以在URL携带,也可以在请求体中携带。但是,一般服务器端只会获取从请求体中获取POST的请求参数。

携带的数据大小是否有限制,限制是多少?

对于GET来说:

一般将请求参数加在URL中,而浏览器和服务器都会对URL的大小加以限制,而且不同的浏览器和服务器对于限制标准设定不同。

jeecgboot前端获取response流 前端get post_GET和POST区别

由于短板是IE浏览器,所以我们一般限制请求URL的大小在2048个字节以下。

jeecgboot前端获取response流 前端get post_GET和POST区别_02

对于服务器来说,目前来看都比浏览器的限制标准宽一点,所以短板还是在浏览器,而浏览器的短板在IE,IE不愧是罪恶源头

所以GET请求携带的数据量,不能超过2KB

对于POST来说:

请求参数都放在请求体中,

jeecgboot前端获取response流 前端get post_HTTP_03

即浏览器只管发,所以一般不做限制,但是服务器会做限制。但是一般来说,默认的限制最多1M或2M。 

请求参数是否可以被缓存?

对于GET来说

GET的请求参数一般被加在URL中,作为URL的组成部分,而URL既可以被当作浏览器书签保存,也会被缓存到浏览器历史记录中,所以GET请求参数可以被缓存

对于POST来说

POST的请求参数一般放在请求体中,而HTTP请求体一般无法被浏览器缓存,所以POST请求参数一般来说无法被缓存。

请求参数的编码方式

对于GET来说

GET请求参数一般被加在URL中,而URL只支持部分ASCII码字符,所以GET请求参数中的非ASCII码字符需要经过url encode编码。常用编码方式有GBK编码,UTF-8编码等,实际编码方式取决于浏览器,比如谷歌内核的浏览器使用的是UTF-8编码。

对于POST来说

POST请求参数一般被加在请求体。由于不是在URL中,所以没有字符必须是ASCII码的限制,可以是任意字符,即POST请求参数一般没有编码要求。除非,指定POST请求参数要被URL编码,如form表单指定enctype为application/x-www-form-urlencode,或者ajax指定content-type为application/x-www-form-urlencode。对于其他格式,如application/json、text/plain都没有编码要求。另外格式multipart/form-data,会对参数值进行多重编码。

请求参数的格式

GET请求参数只能是请求字符串格式(键值对形式)

POST请求参数可以是xml格式(text/xml),json格式(application/json),请求字符串格式(application/x-www-form-urlencode),文件的二进制数据格式(multipart/form-data)

GET和POST在安全性上的差异

对于服务器来说

GET用于获取和检索服务器上的数据,是安全的和幂等的。它仅仅是获取服务器的资源,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。

幂等(idempotent、idempotence)是一个数学或计算机学概念,常见于抽象代数中。

幂等有一下几种定义:

  • 对于单目运算,如果一个运算对于在范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。比如绝对值运算就是一个例子,在实数集中,有abs(a)=abs(abs(a))。
  • 对于双目运算,则要求当参与运算的两个值是等值的情况下,如果满足运算结果与参与运算的两个值相等,则称该运算幂等,如求两个数的最大值的函数,有在在实数集中幂等,即max(x,x) = x。

GET请求的幂等性表现在:对同一URL的多个请求应该返回同样的结果。

注意如果GET请求的资源被服务器端改变了,对于GET本身来说依旧是幂等的,因为结果不是GET导致改变的。

而POST用于创建和更新服务器上的数据,是存在安全问题的,也是非幂等的。

所以服务器通常需要对POST请求参数做一些必要的安全校验。

对于浏览器来说

GET请求参数会直接暴露在URL的地址栏中,虽然会经过URLEncode,但是依旧相当于明文展示,并且GET请求参数会随着URL被缓存在浏览器历史记录中,并且可以被加入到浏览器书签中,增加了数据被盗取的风险。所以,我们一般不使用GET来传递关键数据。

POST请求参数会被加入HTTP请求体中,不会被普通用户直接看到,但是对于开发者来说,依旧可以通过F12键查看Network面板来查看,并且也是明文的。相较于GET而言,POST请求参数不会被默认缓存,也无法被加入书签,所以POST对比GET来说,稍微安全一点。但是本质上还是不安全的。

对于网络传输来说

GET和POST在网络分层模型的传输层中都是基于TCP协议,而TCP协议不会对报文数据段进行加密,相当于明文传输,所以GET和POST请求在网络传输中都是不安全的。

所以目前会在传输层加入ssl协议,对报文数据段进行加密后传输。

GET和POST在性能上的差异

GET和POST在底层都是基于TCP协议传输数据的。都需要通过三次握手建立TCP连接后才能进行数据传输,通过四次挥手才能释放TCP连接,结束数据传输。

所以在建立和释放TCP连接上没有差异。

而网上很多人在说:POST会将HTTP请求头和HTTP请求体分为两次TCP请求发送,但是这实际上可能只是针对部分浏览器来说,我这边使用谷歌内核的Edge浏览器测试并抓包:

jeecgboot前端获取response流 前端get post_GET和POST区别_04

一次HTTP POST请求中,只有一个TCP包

jeecgboot前端获取response流 前端get post_请求参数_05

 一次HTTP GET请求中,也只有一个TCP包

8 Connections (w3.org)中的一段话,来赞成HTTP POST请求会发送两个TCP包。

jeecgboot前端获取response流 前端get post_前端_06

jeecgboot前端获取response流 前端get post_请求参数_07

jeecgboot前端获取response流 前端get post_请求参数_08

 但是作者和网友的讨论,我感觉都有道理。

原问题是:HTTP POST请求会将 请求头和请求体分两个tcp包发送。

这里w3c规范提出如果给HTTP POST请求头加一个Expect:100-Continue 字段,会导致HTTP POST在发送正文消息前,先基于请求头发送一个HTTP请求询问服务器是否接收马上要来的POST请求,如果服务器接收,才会发送基于请求体的HTTP请求。

这里HTTP POST请求是将请求头和请求体分到了两次HTTP请求中,当然也应该算是两个tcp包发送了。

分歧应该在:到底是一个HTTP POST请求产生了两个tcp包,还是两个HTTP请求产生了两个TCP包。

但是anyway,默认情况下,HTTP POST请求只会产生一个tcp包,且请求头和请求体都在该tcp包中。

所以我理解 POST和GET在性能上应该只取决于携带的数据量,由于POST可以携带的数据更多,所以可能在时间上消耗更多,但是底层来看,二者性能应该没有差别。