卡车司机——论Get和Post的区别

605 阅读8分钟

前言

一个很基础的问题,getpost有什么区别 你的心中一定涌现出很多答案
去谷歌百度一下,也会有很多详尽的文章来进行介绍
本文希望通过更形象一点的方式来帮助理解记忆

本质:都只是司机罢了

getpost都是大名鼎鼎的HTTP运输公司手下的卡车司机
旁人问起他们俩:你们具体都是做啥的呀
get说:我负责从请求数据,post说:我负责提交数据

不过他们心里清楚,他们没有能力的差别(都是TCP链接),只是被公司委托了不同的任务,如果必要,也可以捎带着把对方的活也干了
get可以在车厢里(requst body)里塞点私货,post也可以在车顶上(url)放点东西
只要提前跟客户(服务端)沟通好,这样的“走私”是完全行得通的

携带数据:装载方式不同

这里有一颗土豆,{ name : 'Big potato', weight: 20 },等待被装货运输
根据http公司的规定

If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type. The user agent then traverses the link to this URI. In this scenario, form data are restricted to ASCII codes.

If the method is "post" and the action is an HTTP URI, the user agent conducts an HTTP "post" transaction using the value of the action attribute and a message created according to the content type specified by the enctype attribute.

如果是get司机来装货,先用application/x-www-form-urlencoded方法包装(编码),之后以键值对的形式,中间用挡板&隔开,货物改装成 name=Big+potato&weight=20 (空格变成+) 用胶带?贴在车顶(url

不过因为url一定要全是ASCII字符组成。,所以如果货物里面的非ASCII字符,还会被整的面目全非,比如汉字“大土豆”会被整成%E5%A4%A7%E5%9C%9F%E8%B1%86

如果是post司机来装货,默认也是用application/x-www-form-urlencoded方式包装,也变成键值对的形式,放在车厢内(request body),货物里的非ASCII字符可以保持原样。
不过post在装载上就有一点特权了,它可以自己修改车头request head)中的content-type
比如使用multipart/form-data编码,用以文件上传
再就是常用的application/json,数据需要是JSON格式的字符串,所以一般用JSON.stringify(data)先将数据转为字符串,后台用JSON.parse进行解析,这种编码格式可读性更高,比如那个土豆就可以保持原样格式{ name : 'Big potato', weight: 20 }进行传输

数据限制:你只管带,收不收看我

上文也提到了,get司机的车上只能带 ASCII字符,不然虽然你可以带个毁了容的货,但是一来不美观,二来服务端处理起来也不反便,而post就没有这样的限制
而在货物大小上,其实get的车和post的车本身都是够大的,想装多少装多少,但是很多道路,还有客户的门上都有限高post的车是没什么,但是get的车顶上的货物就会被削掉,真正的“你只管带,我收了算我输”
换句话说,就是浏览器和服务器对url的长度有所限制,而get又是会把数据放在url中的,所以就有了get传数据有长度限制一说,而如果很不幸本来的车顶就很高(url很长)的话,那么预留给get司机的载货空间就更小了

浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。

货物安全:五十步笑百步

其实这哥俩安全性都好不到哪里去,都是在http明文传输的大马路上招摇过市,在稍微专业一点的劫匪眼中,基本上就是裸奔的羔羊,只要被人抢劫了(抓包),货物数据也就泄露了,除非你跑https,可以进行加密
不过他俩还是有五十步笑百步的区别的,get相对而言更差一点,由于它的货物都在车顶,一路上的监控探头都能拍到它的样子,也就是可能会被浏览器缓存下来,同时在历史记录里也能看到,所以哪怕是一个毫无技术的菜鸟劫匪,只要扒下探头看两眼也就知道货物是啥了

重复提交:避免恶果

相比post来说,get是比较执着的,也比较愣头愣脑
如果道路崎岖(网络不好),一次没跑通,那么get请求可能会重复多次,post则不会

如果只是请求数据也就算了,但是如果是一些有副作用的事,比如让服务端增删东西,执着的get一次次重复告诉服务端要干嘛干嘛,傻傻的服务端也都照章办事,那可能会造成意想不到的恶果
所以公司规定,get你这二愣子就专注自己的本质工作,请求数据
我们要保证的是,get幂等性,即一次请求和多次请求,造成的后果应该一致

对于单目运算,如果一个运算对于在范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。

运输速度:get略胜一筹?

通告:有些文章撰文称,post司机很礼貌,进客户门前会先敲个门问一下,然后再进去,也就是发两个TCP数据包,经公司调查,这是误解,那不是post本人的行为,是一些浏览器和ajax请求方式的特殊的行为,特此澄清
既然不是固定行为,那就不能说因此get是比post快的了,而且其实post车上唯一比get的车重的地方,就只有那几个描述数据的首部字段(如content-type),也就是轻飘飘的贴在车头的纸,对车速的影响实在微乎其微
实在要说的话,就是post还有个把数据封包进车厢的过程,但只要电脑配置不至于太差,这点时间也是微乎其微,所以getpost的速度其实是差不多的

更好的管理方法:Rest

其实区别已经讲完了,这里多提一个概念,是Rest http公司里其实还有两个小伙伴,putdelete,分别对应增删

但由于早期的Web MVC框架设计者们并没有有意识地将URL当作抽象的资源来看待和设计,所以导致一个比较严重的问题是传统的Web MVC框架基本上都只支持GET和POST两种HTTP方法,而不支持PUT和DELETE方法。所以导致post承担了很多额外的任务。

rest的设计理念,就是通过url来暴露资源,而通过操作来表明要做什么,通过code可以很清楚地知道是哪里的错误 比如:左边是平常的设计,而右边是rest的设计

GET /api/getPatatoes --> GET /api/Patatoes 获取所有土豆
GET /api/addPatatoes --> POST /api/Patatoes 添加一个土豆
GET /api/editPatatoes/:potato_id --> PUT /apiPatatoes/:dog_id 修改一个土豆
GET /api/deletePatatoes/:potato_id --> DELETE /api/Patatoes/:potato_id 删除一个土豆
更为简洁,而且组织非常清晰

总结

总结一下的话,如果以后被问到这个问题,可以回答

  1. 本质上它们都是TCP链接,没有根本的区别
  2. get的参数会被编码拼贴进url,而post的数据是封装在请求体内的,并且可以根据content-type来更改编码的方式
  3. 在数据限制上,get只能传ASCII字符,并且由于浏览器和服务端对于url长度的限制,也就变相对get的数据长度有了限制,post则没有限制,
  4. 在安全性上,它们都是明文传输,不过get由于参数暴露在url中,会被浏览器缓存,同时存在在历史纪录中,所以安全上还要更差一点
  5. 为了避免get重复请求带来副作用,要保证get的幂等性
  6. 最后,在速度上只有微乎其微的区别,可以忽略不计

希望本文对于你们理解记忆这个问题有所帮助

参考资料

W3C官方答案 www.w3school.com.cn/tags/html_r…
关于Get只接受ASCII字符的问题 segmentfault.com/q/101000001…
x-www-form-urlencoded Vs json HTTP POST stackoverflow.com/questions/1…
深入理解POST的本质 blog.51cto.com/cnn237111/1…
99%的人理解错 HTTP 中 GET 与 POST 的区别 www.oschina.net/news/77354/…
GET 和 POST 区别?网上多数答案都是错的! juejin.cn/post/684490…
浅谈HTTP中Get与Post的区别 www.cnblogs.com/hyddd/archi…
都 2019 年了,还问 GET 和 POST 的区别 blog.fundebug.com/2019/02/22/…
怎样用通俗的语言解释REST,以及RESTful? www.zhihu.com/question/28…