技术分享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 来优化网站性能。但这样做显然是不太好的,因为:
-
GET与POST都有自己的语义,不能随便混用。
-
据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
-
并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
为什么说 GET 比 POST 快?
1 POST 请求包含更多请求头
因为 POST 需要在请求的 Body 部分包含数据,所以会多了几个数据描述部分的首部字段(如 Content-type),但这个方面的影响是微乎其微的
2 POST 要先将请求头发送给服务器确认
GET 请求的过程
- 浏览器请求 TCP 连接(第一次握手)
- 服务器答应进行 TCP 连接(第二次握手)
- 浏览器确认,并发送 GET 请求头和数据(第三次握手,这个报文比较小,所以 HTTP 会在此时进行第一次数据发送)
- 服务器返回 200 OK 响应
POST 请求的过程
- 浏览器请求 TCP 连接(第一次握手)
- 服务器答应进行 TCP 连接(第二次握手)
- 浏览器确认,并发送 POST 请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
- 服务器返回 100 continue 响应
- 浏览器开始发送数据
- 服务器返回 200 OK 响应
3 GET 会将数据缓存起来
OverView | |
---|---|
GET | |
POST |
Cache | |
---|---|
GET | |
POST |
经测试,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 | 博客园