为什么要区分Get和Post?

Get和Post的区别,大多数人都会有了解。但是我有个疑问,既然这两种请求方式同样基于TCP/IP,就代表了他们只是规范上有一些区别而已。那么为什么要区分Get和Post这两种请求方式呢?

看了一些资料后,总结一下我对这个问题的看法。

 

一、Get和Post的一些区别

(1)HTTP/1.1强制要求服务器支持Get,但是没有要求Post

Get通常用于请求服务器的某个资源。在HTTP/1.1中,强制要求服务器实现Get方法。

Post请求方法起初是用来向服务器输入数据的。在HTTP/1.1中,POST方法是可选被实现的,没有明确规定要求服务器实现。

(2)因为url的长度限制,Get请求不能代替Post请求发送大量数据

RFC 2616中对url的长度并没有限制(不是http的规范在限制长度)。限制是由不同的浏览器和服务器制定的。

试想,如果url长度无限制,会发生什么?

你的浏览器在处理超长url时,可能需要投入更多的资源去解析请求,使处理速度下降,导致浏览体验很“卡”。服务器在解析超长的url也会消耗更多资源(处理超长的请求等同于处理超长字符串)。

以上情况在现实中都会被视为攻击行为,是需要警惕的。所以,实际上的url长度限制不是Get和Post规定的,而是由浏览器和服务器共同决定的。

(3)不存在“发送的数据更少”

在一般情况下,Post的请求头会比Get多一些属性,仅此而已,不存在“发送的数据更少”。

具体的差异只要打开Postman发送几个请求就知道了,不在这里深入研究。

(4)Post请求不能被缓存吗?

在很多资料上有这样一种说法:如果Get访问静态资源,浏览器会自动缓存(不同浏览器对此功能可能有不同设置),但是Post则不能。

这种现象只能说明很多浏览器不对Post请求做缓存处理,并不能说明Post请求不能被缓存。“Post请求不能被缓存”的这种观念只是习惯带来的错觉而已。

在RFC 2016中提到:Get和Post以及Head都是可以被缓存的。

在实际使用过程中,对Http请求的优化大多数都放在Get请求上,比如对没有数据变化的请求(网站中常用的静态文件)做缓存。所以在潜意识中我们认为只有Get请求才可以被缓存,从而不会考虑Post请求的缓存优化。

事实上,因为Get和Post两种请求的目的不同,Post在大部分情况下确实不需要做缓存处理,所以我们不做。但是这不代表不能做缓存处理。

(5)Post相对Get是“比较安全”的

Post要比Get安全一点点。注意,是一点点…

说这两者都是明文传送当然是没有错的了,但是这里有一个细节,就是Get的url会被放在浏览器历史和web服务器日志里面。POST发完基本就木有了。

所以,如果你把关键数据放在GET里面,被人偷窥了浏览器,或者WEB服务器被入侵日志被人导去了,那就100%泄露了。至于,日志没有记录,只要数据库服务器不被入侵,基本还是安全的。

当然,如果被抓了包,这一切都没有什么卵用,所以,Https该用还是得用。

(6)100 continue存在吗?

什么是100 continue?

有一种说法:Get产生一个tcp数据包;Post产生两个Tcp数据包。

对于Get方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)。而对于Post,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

换个意思:post在真正接受数据之前会先将请求头发送给服务器进行确认,然后才真正发送数据。

根据RFC 2016,这只是一种极端情况罢了(可以自己设置这种Post方式),这种说法在平时是无法遇到的,是一个错误的观念。

二、为什么要区分Get和Post?

(1)使用目的不一样

在常识中,使用这两种方式的使用目的不一样,所以服务端可以根据不同的请求方式做出不同的处理。

1.根据HTTP规范,get用于信息获取,而且应该是安全的和幂等的

get表达的是一种幂等的,只读的,纯粹的操作,即它除了返回结果不应该会产生其它副作用(如写数据库),因此绝大部分get请求(通常超过90%)都直接被CDN缓存了,这能大大减少web服务器的负担。

“幂等性”:幂等是一个数学/计算机科学的概念,我理解为:多次相同输入会有相同结果。

在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。

那么问题来了,如果使用get访问接口进行查询(查询数据是可变的),那么get的结果应该是可变的,这种情况还能把get称之为“幂等”吗?

我个人认为这是理解问题。如果使用get获取静态资源,那么当然是幂等的。如果获取一些动态资源(比如上面提到的查询的结果),“相同结果”应该理解为“成功查询到结果”,而不是“每次查询的结果都一模一样”,应该可以理解为“具有幂等性”。

2.根据HTTP规范,POST表示可能修改变服务器上的资源的请求

post所表达的语义是非幂等的,有副作用的操作,所以必须交由web服务器处理。如果把所有get请求换成post,意味着主干网络上的所有CDN都废掉了,web服务器要处理的请求数量将成百上千倍地增加,显然这不是一个聪明的做法!

(2)如何看待“get和post就是那几个字母的区别”这种言论?

开发过web服务器的同学都知道,只要请求传递到了服务器上,那么要怎么解释这个请求的内容就完全是服务器自己的事情了,只是web服务器开发框架通常会自动帮你做一些解析http请求的事情而已。

所以如果说客户端和服务端都是自己写,那当然很随意,想怎么玩就怎么玩好了,事实上在没有RESTful建议的时候,大家也的确玩得很随意。

然而说出“就是几个字母的区别”这种话仅仅是表达了“我搞过服务端开发”这层意思而已。

实际上问题真正困难的地方在于,网络上每天产生的请求数目庞大,并且其中绝大部分请求均为只读请求,如果所有这些请求都要交由web服务器直接处理,这无疑是巨大的资源浪费。

所以大家自然能想到,假如我们能在请求到达web服务器之前,就对请求作一个初步的解析,得知请求的大致意图,对于不同意图的请求以不同方式满足(比如请求经过nginx的时候nginx就会解析请求头信息,然后根据这些信息把请求分配给合适的角色去进一步处理),那么事情就合理多了。

于是RESTful的建议就在这个时候应运而生了,它的出现正是为了解决http基础设施未能得到充分合理利用的问题。

(3)我的理解:

为什么要区分Get和Post?

因为适用的情景不同,所以要区分不同的请求方式,从而充分利用web资源区分并不是强制的,而是现实的业务告诉我们,某种业务用某种方式更加合理。久而久之,就变成一种习惯了,大家都会自发地遵守下去。

3.总结

只是单纯会用是不够的。常常问下自己为什么,也许能得到更深的体会。

参考资料如下:

https://www.zhihu.com/question/31640769?rf=37401322

https://segmentfault.com/a/1190000004014583

https://www.w3.org/Protocols/rfc2616/rfc2616.html