关于post和get请求的区别 请求报文
很多人在学习web知识的时候容易产生一种惯性思维,那就是觉得get方法就是从服务器取得数据;post方法就是向服务器提交数据。造成这种思维的原因,大概就是我们在学习面向对象编程的时候学过类的get()方法和set()方法,容易把这种概念类比到HTTP协议的概念里面。哪怕是我身边有一定工作经验的程序员都有可能产生这种思维。
HTTP协议是运行在计算机网络应用层的网络协议。它由两个程序实现,一个是服务器,一个是客户端。一个网站要想能够被访问,必须要用一个服务器来存储所有相关的图片,文档,程序等等的数据。这个服务器可能就是在一个机器上面运行的THHP server程序,例如tomcat, nginx等等。浏览器就是我们使用的客户端,我们在浏览器的地址栏输入支持http协议的web服务器ip地址或者域名,端口号,还有路径,就可以访问web server上面的网页了。
HTTP协议约束了 web server 和 client 之间如何通信。它们通过发送报文,进行通信。客户端向服务器发送请求报文,服务器收到请求报文后根据客户端的请求,发送一个响应报文。此文着重讲解一下 post 和 get 方法之间的区别和联系。
首先关于get与post区别
很多人首先想到
1、最大的不同是参数的传送机制不同,post的容量更大,更安全。
2、get方式下,要传的参数放在url地址里,有长度限制。post方式下,要传的参数是放在http传输体里。
3、get和post请求对于表单提交来说,get是显示提交,post是隐式提交;post安全性要高点。
其实还有其他的区别之处
还有一个区别,简单的说:
GET产生一个TCP数据包;POST产生两个TCP数据包。
长的说:
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。
因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此有团队推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?
原因有三点:
-
GET与POST都有自己的语义,不能随便混用。
-
据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
-
并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
然后再说下请求报文
首先一个request的报文可能是这样:
POST /path/of/resource HTTP/1.1
Host: IP:PORT
Authorization: Basic YXBpdXNlcjpmbnN0MTIzNA==
User-Agent: curl/7.59.0
Accept: /
Content-Length: 31
我们看到的第一行,就是报文的请求行 。POST 表示这次http请求的方法是post方法。 然后是路径, http协议。 请求方法可以是以下几种:get post put delete head 。post会将参数保存在body中,而get方法不会。 如果发送一个携带参数的get 请求,我们的参数会体现在url中。
用curl发送一个get请求:
curl -v -X GET -i “http://ip:port/path?aaa=1&bbb=44d”
我们的参数会被存在request报文的body中:
POST /path HTTP/1.1
Host: 10.167.157.49:5001
Authorization: Basic YXBpdXNlcjpmbnN0MTIzNA==
User-Agent: curl/7.59.0
Accept: /
Content-Length: 31
Content-Type: application/x-www-form-urlencoded
upload completely sent off: 31 out of 31 bytes
HTTP 1.0, assume close after body
从上面的request报文可以看到,上传了body。
以上,我们可以看出http 请求一个网页的时候,post方法和get方法都可以向服务器提交表单。但是我们一般看到的都是用post方法,只是为了保护表单中数据的私密性,为了不让用户的输入暴露在url中。其实get方法也可以提交表单,不过表单的输入都体现在了url里而已。