一、前言
今天研究了一下HTTP协议中,GET方法与POST方法的区别。一研究发现,GET和POST完全不似我学习Web开发时了解的那般,它们之间的关系完全颠覆了我之前的理解。这篇博客我就来从两个层面谈一谈GET与POST的区别——浏览器层面以及报文层面。
二、正文
2.1 浏览器层面的区别
GET和POST方法在浏览器层面的区别大部分人或多或少都知道一些,它主要包含以下几个方面:
通过以上区别,我们归纳为以下两点:
GET:它用来向服务器请求资源,所以没有副作用,而且它是幂等的,可以被缓存;
POST:用来请求服务器修改数据,所以有副作用,它是非幂等的,不能被缓存;
HTTP中的幂等:每次请求会产生同样的副作用。
GET是幂等的,因为它只是请求资源,不会对服务器产生影响,也就是没有副作用,所以是幂等的;而POST请求不是幂等,因为它修改了数据,每一次请求都会再次造成副作用。
上面列举的这些区别,实际上有一些是存在因果关系的,比如POST用来请求服务器修改数据,所以每一次POST请求在理论上都会对服务器的数据进行修改,正因为如此,才有了这几条:
刷新时需要重新提交数据,以获取最新的资源;
不可缓存,因为POST请求会修改资源,所以缓存旧资源没有意义;
浏览器将GET请求的数据放入URL中,而POST请求的数据放入body中,所以才有了下面几条:
POST请求更加安全,因为GET请求直接将数据放入URL中,用户直接可以看到,但是POST的数据放入body中,用户无法直接看见;
GET请求的数据只允许ASCII字符,因为数据在URL中,URL中只允许ASCII字符,而POST数据放入body中,body中允许二进制数据;
但是,以上这些区别都是浏览器以及Web服务器遵循HTTP的约定实现的,并不是GET和POST的本质区别,下面我们从报文层面分析GET和POST的区别。
2.2 报文层面的区别
这里我直接给出结论:GET方法和POST方法本质没有太大区别,仅仅报文格式以及方法名称不同。不论是GET方法还是POST方法的报文,都是HTTP报文,而HTTP是基于TCP/IP做数据传输的,也就是说,在传输层,这两种方法的报文传输方式没有任何的区别。在约定中,GET方法的数据被放入URL,而POST报文的数据被放入body就是格式上的区别,但是这也不是绝对的。
2.3 深入理解它们的区别
下面我就从本质层面来说明对以上所说的区别做一个解读:
(1)GET方法用来向服务器请求资源,而POST方法请求服务器修改数据
这一点正是HTTP规范中对这两个方法的约定,但是,仅仅只是约定,并不是强制。也就是说,我们完全可以通过GET方法请求服务器修改数据,而通过POST方法向服务器请求资源。对于很多Web开发的初学者,应该都干过类似的事情,比如做使用Servlet或者SpringMVC做Web开发,混用GET与POST。所以说,对于这一条区别,并不是一定的。
(2)GET方法数据被放入URL,而POST放入body
这是也是HTTP规范对这两种方法报文的约定,而浏览器在创建请求报文时是遵照这个约定实现的,仅此而已。这也就是说,对于GET请求,我们也可以将数据放入body中,而对于POST的数据,我们也能够放入URL中。我们违反这个约定,报文依旧可以正常传输,只要服务器的实现支持,就能够正常的获取数据。
(3)GET方法发送的数据有限制(长度和类型),而POST没有
我们前面说过,GET方法只能发送ASCII字符数据,且数据的长度是有限制的,而POST可以发送二进制的数据,且长度没有限制。首先从数据类型来说,不是GET方法只能发送ASCII字符数据,而是URL中只能放入字符数据,而GET方法的数据被放入URL,自然只能被URL所限制。如果我们在GET报文的body中放入数据,照样能够放入二进制数据。再来说说数据长度,HTTP规范中并没有限制URL的长度,真正限制URL长度的是浏览器,浏览器为了方便处理数据,以及安全性考虑,对URL的长度做了限制。但是,HTTP规范并没有限制URL长度,我们完全可以通过编写代码的方式,创建一个包含很长很长的URL的HTTP报文,是可以正常传输的。
(4)POST方法比GET方法更加安全
这种说法的依据就是浏览器不会把POST的数据放入URL,用户不能直接看见,所以认为POST更加安全。但是在数据传输的过程中,GET和POST的报文传输是没有区别的,都是通过TCP连接进行传输。只要我们通过抓包软件,抓取到了HTTP报文,其实它们携带的数据都是直接可见,没有任何安全性可言。所以,从严格意义上来讲,GET和POST的安全性没有太大区别。若想要安全,应该使用HTTPS。
(5)POST请求会发送两个TCP报文
网上还流传着它们之间的另一个区别,就是说浏览器会将POST请求的header和body分开来发送,产生两个TCP报文段,先发送header,接收到服务器响应的状态码100之后,再发送body部分。但是,HTTP规范中并没有明确说明这一点,而且在实际的测试中,也没有发生这种情况。所以可以认为,这只是某些浏览器的自主实现,并不是POST的必然行为。
三、总结
我们谈论GET和POST的区别时,应该像上面一样,分情况进行讨论。在浏览器层面,它们之间有许许多多的区别,有些是HTTP规范的约定,而大部分其实还是浏览器的自主实现;而从本质上来看,两种其实没有太大区别。