技术分享09 - 详述GET和POST的区别

“标准答案”

GET和POST是HTTP请求的两种基本方法,在面试中被问到它们的区别,内心总是一阵窃喜,然后熟练地说出这些“标准答案”:

  • GET 在浏览器回退时是无害的,而 POST 会再次提交请求。
  • GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以。(除非手动设置)
  • GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置。
  • GET 请求只能进行 URL 编码,而 POST 支持多种编码方式。
  • GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。
  • GET 请求在URL中传送的参数是有长度限制的,而 POST 没有。
  • 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。
  • GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。
  • GET 参数通过 URL 传递,POST 放在 Request body 中。

(本标准答案参考自w3schools)

深入

其实,GET 和 POST 本质上是一样的

HTTP的底层是TCP/IP,GET 和 POST 是 HTTP 协议中的两种发送请求的方法。所以 GET 和 POST 的底层也是TCP/IP,也就是说,GET/POST 本质上都是 TCP 连接。GET 和 POST 能做的事情是一样的:如果要给 GET 加上 request body,给 POST 带上 URL 参数,技术上是完全行的通的。

举个例子

在万维网的世界中,TCP 就像汽车,我们用 TCP 来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那么这个世界会看起来是非常混乱:送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则 HTTP 诞生了。HTTP 给汽车运输设定了好几个服务类别,有 GET、POST、PUT、DELETE 等等。HTTP 规定,当执行GET请求的时候,要给汽车贴上 GET 的标签(设置 method 为 GET),而且要求把传送的数据放在车顶上( URL 中)以方便记录。如果是 POST 请求,就要在车上贴上POST 的标签,并把货物放在车厢里。当然,你也可以在 GET 的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在 POST 的时候在车顶上也放一些数据,让人觉得傻乎乎的。

HTTP 只是个行为准则,而 TCP 才是 GET 和 POST 怎么实现的基本。

既然我们知道了他们本质上没有区别,为什么“标准答案”中会说它们的参数长度是有限制的?

在万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起 HTTP 请求)和服务器(接受 HTTP 请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限地堆货物(URL 中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。(大多数)浏览器通常都会限制 URL 长度在 2KB,超过的部分,恕不处理。如果你用 GET 服务,在 Request body 偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然 GET 可以带 Request body,但不能保证一定能被接收到,所以不推荐我们这样做。

GET/POST 参数长度限制

GET 请求

HTTP GET 方法提交的数据大小长度并没有限制,HTTP 协议规范没有对 URL 长度进行限制。
目前说的 GET 长度有限制,是特定的浏览器及服务器对它的限制。

各个浏览器和 Web 服务器的最大长度总结

浏览器
(1)IE:IE浏览器(Microsoft Internet Explorer)对 URL 长度限制是 2 083(2K+53),超过这个限制,则自动截断(若是form 提交则提交按钮不起作用)
(2)Firefox:Firefox(火狐浏览器)的 URL 长度限制为 **65 536 **字符,但实际上有效的URL最大长度不少于100 000个字符
(3)Chrome:Chrome(谷歌)的 URL 长度限制超过 8182 个字符,服务器返回 414
(4)Safari:Safari 的 URL 长度限制至少为 80 000 字符
(5)Opera:Opera 浏览器的 URL 长度限制为 190 000 字符,Opera9 地址栏中输入 190 000 字符时依然能正常编辑

服务器
(1)Apache:Apache 能接受 URL 长度限制为 8 192 字符
(2)IIS:Microsoft Internet Information Server(IIS) 能接受 URL 长度限制为 16384 个字符,这个是可以通过修改的(IIS7)

POST 请求

理论上讲,POST 是没有大小限制的。HTTP 协议规范也没有进行大小限制,起限制作用的是服务器处理程序的处理能力。

Tomcat 下默认 POST 长度为2M,可通过修改 conf/server.xml 中的 maxPostSize=0 来取消对 POST 大小的限制。

重大区别

事实上,在它们发送请求的过程中,GET 请求产生一个 TCP 数据包,而 POST 产生两个 TCP 数据包:

对于 GET 方式的请求,浏览器会把 HTTP Header 和 Data 一并发送出去,服务器响应 200 OK(返回数据);而对于 POST,浏览器先发送 Header,服务器响应 100 continue,浏览器再发送 Data,服务器响应 200 OK(返回数据)。

因为 POST 需要两步,时间上消耗的要多一点,看起来 GET 比 POST 更搞笑。因此 Yahoo 团队有推荐用 GET 替换 POST 来优化网站性能。但这样做显然是不太好的,因为:

  1. GET与POST都有自己的语义,不能随便混用。

  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。

  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

为什么说 GET 比 POST 快?

1 POST 请求包含更多请求头

因为 POST 需要在请求的 Body 部分包含数据,所以会多了几个数据描述部分的首部字段(如 Content-type),但这个方面的影响是微乎其微

2 POST 要先将请求头发送给服务器确认

GET 请求的过程

  1. 浏览器请求 TCP 连接(第一次握手)
  2. 服务器答应进行 TCP 连接(第二次握手)
  3. 浏览器确认,并发送 GET 请求头和数据(第三次握手,这个报文比较小,所以 HTTP 会在此时进行第一次数据发送)
  4. 服务器返回 200 OK 响应

POST 请求的过程

  1. 浏览器请求 TCP 连接(第一次握手)
  2. 服务器答应进行 TCP 连接(第二次握手)
  3. 浏览器确认,并发送 POST 请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
  4. 服务器返回 100 continue 响应
  5. 浏览器开始发送数据
  6. 服务器返回 200 OK 响应

3 GET 会将数据缓存起来

OverView
GET image
POST image
Cache
GET image
POST image

经测试,Chrome 下和 Firefox 下如果检测到 GET 请求的是静态资源,则会缓存,如果是数据,则不缓存(但是 IE 啥都会缓存起来)。

当然,应该没人会用 POST 去获取静态数据吧。

4 POST 无法管道传输

在 HTTP/1.1 中,有一种称为管道网络传输的通信方式:把需要发送到服务器上的所有请求放到输出队列中,在第一个请求发送出去后,不等到收到服务器的应答,第二个请求紧接着就发送出去,但是这样的方式有一个问题,那就是,如果一个管道中有 10 个连接,在发送出 9 个后,服务器突然告诉你,连接关闭了,此时客户端即使收到了前 9 个请求的答复,那也只能将那 9 个答复清空。此时,客户端的这 9 个请求需要重新发送。

这对于幂等请求还好(比如 GET,多发送几次都没关系,每次都是相同的结果),如果是 POST 这样的非幂等请求(比如支付的时候,多发送几次就惨了),肯定是行不通的。

所以,POST 请求不能通过管道的方式进行通信!

总结

  • GET 在浏览器回退时是无害的,而 POST 会再次提交请求。
  • GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以。(除非手动设置)
  • GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置。
  • GET 请求只能进行 URL 编码,而 POST 支持多种编码方式。
  • GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。
  • GET 请求在URL中传送的参数是有长度限制的,而 POST 没有。
  • 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。
  • GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。
  • GET 参数通过 URL 传递,POST 放在 Request body 中。
  • GET 一般来说提交的数据最大是2k;POST 理论上没有限制,实际上IIS4中最大量为80k,IIS5中为100k。

参考资料

GET和POST两种基本请求方法的区别 - 在途中# | 博客园

GET 和 POST 请求的优缺点和误区 - beaning | 博客园

Get请求与Post请求的区别 - kingon | 博客园

为什么get比post更快 - bbenst | CSDN

Ajax中Get请求与Post请求的区别 - Localhost | 博客园