生产问题:出现重复创建数据漏洞,架构师级别的排查思路(下)Get请求和Post请求到底有什么区别?该怎么用?
Get请求和Post请求,到底有什么区别?
这是一个前几年非常高频的面试题,随着大家整体水平的提高,这道题逐渐淡出了。但是,在我实际接触到的人里面,能真正认识到其中区别的人并不多。那么,在Restful风格接口普及的今天,好好认识HTTP的每一个Method就更有必要了。
所以,本文,就来分析分析HTTP的Method的区别(包括但不限于Get,Post),以及它们都有哪些坑。
Get和Post的区别,我们能百度到的很多回答没讲到核心内容
- 安全:Get不安全,Post安全。这个说法来自于Get请求的参数会被直接携带在URL里,Post请求的参数是放在Body里的,而URL就不安全。这一点,在曾经还有点道理。因为以前,很多请求发起就是由浏览器携带参数,跳转到后台,然后后台再重定向到渲染好资源的页面资源。但是现在,前后端分离,基本上跳转都已经不存在了。Get请求和Post请求,都是异步发起,然后动态更新资源,不存在Get请求会暴露参数的问题了。所以安全这个说法,放在如今,实在是太勉强了。
- 参数长度:Get参数长度更短,如果要传数据比较大的参数需要通过Post。Get参数长度的限制确实比较有限,但也并不是它们的核心区别。Get就算参数再有限,对于90%的请求传参都是够用的。那为什么还有那么多请求是用Post发送的呢?所以说,这个说法,也有点勉强。
- 缓存:Get资源会被缓存,而Post资源不会。这个算区别,但不是本质区别。因为其实现在的前端技术,POST请求如果有数据返回,也可以进行缓存。
那么,区别到底在哪呢???
其实,在底层实现上没有任何区别。Get和Post都是通过TCP/IP连接。只要你想的话,甚至可以Get用Body传参,Post用URL传参,在技术上,都是可以实现的。
先别急着打我,接下来就要说它们真正的区别了。
Get和Post 真正的区别
既然技术上Get和Post没有区别,那他们的区别在哪里呢?其实真正的区别就在于——语义。那些种种区别,其实都是语义带来的。
学生:老师!HTTP的GET和POST请求到底什么区别呀?
老师:还记得你让人传话你小跟班帮你买早餐,结果买多了的那事吗?
学生:当然记得!一提这我就来气。
学生:当时我喊小胖帮我传话给我小弟带份饭给我,我看他趴桌子上一动不动,以为他在睡觉。我抄完卷子看他睡醒了,又喊他传话我小弟帮我带饭。谁知道,他之前就已经给我小弟传过话了,这次他以为我想吃两份,又传了一次。小弟也是个憨憨,居然真就买了两份回来。
老师:为什么会出现这种情况呢?就是因为小胖对你要带话的行为没有正确的理解,你喊一次他就做一次。
学生:是啊,那次之后我就交代小胖了,以后我喊多次也只帮我处理一次就好了。
老师:然后呢?就发生了你交白卷的操作是么?
学生:老师,您就别揭我伤疤了!
学生:那次考试,我一道题都不会写,我让小胖帮我找我小弟给我写份答案。结果写的太潦草,我一个字都不认识。没办法啊,我就让小胖再重新去帮我要一份。
学生:结果呢?结果到收卷子的时候,也没等到传来下一份答案。问他原因,他居然说是我教的“只处理一次就好了”,我真是气不打一处来。
老师:你们这就是没有共识的结果,没有对传话的内容做合理的约定。你们的约定啊,应该是:如果涉及花钱的传话,就不要多次传。如果是要答案这种事情,不用花你的钱的话,那就可以多次传递。
老师:GET和POST也是这个区别。在HTTP协议中,这两个 Method 在使用过程中几乎没有区别。POST能做的,GET都能做,反过来也一样。核心区别在哪呢?
老师:没错,就是语义!在网络世界中,路由器、交换机、网管、拦截器、负载均衡、CDN、缓存有若干的网络组件与网络插件。它们如何判断你到底想干啥呢?没错,就是HTTP Method,也就是GET和POST(当然还有PUT,DELETE等)。
老师:所有的网络元件,大家定义一个共识。GET请求就是用来查询数据的,因为你是查询数据,不会带来负面影响,所以就可以允许自动重发,可以被缓存等。
老师:但是,反过来你想一下。POST请求有部分类似于转账请求。可以被重发么?
学生:那当然不行,转账请求如果被重发了,我本来想给老师发5¥红包,但是万一网络一抖动,闹不好我这个月生活费就没了!
老师:对,诸多网络组件也是这么约定的。它们一看,啊,你这是个POST请求,一定是个不希望重发的请求,就算抓发的时候没收到响应,也不会帮你多次转发啦。
学生:难怪转账没有发生过重复转账的行为,原来是这样啊!
老师:嗯哼~
其实,Get和Post的区别,也在这里。这是一种HTTP协议的一种约定。在语义上把它们区分开(实际上不仅限于GET和POST):
- GET - 从指定的资源请求数据。
- POST - 向指定的资源提交要被处理的数据。
至于那些细节的特性,全都是基于这些最基本的语义。比如缓存,GET被认为是请求资源,所以可以被缓存。而POST被认为是提交数据,所以不可以被缓存。重发也一样,GET是请求资源,所以很多网络转发的中间件会对其自动重发。而POST是提交数据,所以一般不会重发。
这些语义特性不是强制的。如果,你自己写的网络中间件,为了防止重发带来的问题,你也可以选择对于所有请求一视同仁。只不过,这不符合规范,不推荐这么做而已。
拓展
其实类似的场景还有很多。比如在Java技术栈中,get方法用于获取属性,set方法用于设置属性。甚至,诸多框架就针对Getter,Setter方法做了增强,并要求对象的类,必须要有Getter,Setter方法。你如果硬要问“我的Getter方法用来做其他的事行不行?”。我只能说,不是不可以这么用,只是这样用不符合规范,会有很多麻烦。就像HTTP的GET请求会被重发一样,很多工具和框架对于Getter和Setter的很多增强处理,可能会因为你违反了通常的Getter的规范,而出现反直觉的结果。所以,尽可能还是避免这样的操作。
感谢
感谢能阅读到这里的你!
希望本文对你可以有帮助,存在的漏洞以及待完善的地方也欢迎指出!
期待你的点赞,收藏,以及关注!你的支持,是我继续更新的最大动力!