Http的Get Post


初识

第一次接触get和post,只是知道get是将参数加在url后面,Post是将参数加在表单里,然后说Get是不安全的,因为将信息都放在了url里,而Post将参数隐藏起来,其他的并不知道很多,但这可以说是非常浅薄的.

更多区别

后来我学习更多的web相关知识,知道了更多对的区别,列一下w3schools中的对比:

  • GET后退按钮/刷新无害,POST数据会被重新提交(浏览器应该告知用户数据会被重新提交)
  • GET书签可收藏,POST为书签不可收藏。GET能被缓存,POST不能缓存 。
  • GET编码类型application/x-www-form-url,POST编码类型 encodedapplication/x-www-form-urlencodedmultipart/form-data。为二进制数据使用多重编码。
  • GET历史参数保留在浏览器历史中。POST参数不会保存在浏览器历史中。
  • GET对数据长度有限制,当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。POST无限制。
  • GET只允许 ASCII 字符。POST没有限制。也允许二进制数据。与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET !POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。GET的数据在 URL 中对所有人都是可见的。POST的数据不会显示在 URL 中。

但事实真的是这样吗?

浏览器请求

我们知道,Get,Post是Http中的方法,是什么事方法,也就是http请求报文中请求行中的Method.同时还有Put,Delete等,为什么有这些方法呢?事实就是,其实这只是个规范,并不是一定要这样.
我们知道,Http在五层网络协议中处于最高层,也就是应用层,而下一层使用的是TCP协议,而根据Http的协议内容,没有要求说Get就一定不能有body,Post就不能把参数加在url后面,只能说这些规定和上面的区别只是一个东西规定的,那就是浏览器.
我们最常用的发送http请求的就是浏览器了,我们从地址栏输入url,一般都是Get请求,而在页面提交表单,就是post请求.为什么这样规定呢,就是因为浏览器只有几种,而网站有亿万种,怎么才能让浏览器能访问所有网页呢,这就需要规定,不然你的网站就别让别人看见.所以有上面那些区别,都是因为浏览器.

这里说的浏览器,更多的是指一些原生的浏览器操作,不包括ajax发送请求的方式,原生的浏览器操作中, get请求例如地址栏输入网址或者点击<a/>标签,post的话,就是使用<form> 标签,浏览器的get操作只能由url触发,所以我们如果想要携带参数,必须使用querystring,而post请求如果想使用querystring, 也非常简单,只要使用<form action="url"> 即可。

接口请求

那么除了浏览器,还有什么使用http请求呢,那就是我们开发使用api接口了,常见的有很多,我熟悉的就是python的requests和Java的commons-httpclient或者okhttp,当然还有很多工具,比如linux的curl和很多人用过的postman,我就拿Python来说说.
我们先看一下requests库中的方法,这是一个http客户端的库,就看一下Get和Post:
def get(url, params=None, **kwargs):
def post(url, data=None, json=None, **kwargs):
可以看到其实get和post一样,都是传入一个参数,不过名字不一样,一个是params,另一个是datajson(data和json的区别自行查找). 其实我不知道底层,也可能get会把params里的参数变成url?key=value&key2=value2这样的形式,但是这还是因为浏览器对网站的规范,那怎么证明呢?我们自己写个接口服务呗!
还是Python,我们就用Flask.先看一下Flask的Get服务.

@app.route('/')
def hello_world():
    return 'Hello, World!'

这其实看不出什么区别,我们可以看一下,flask中Get和Post是怎么拿参数数据的.
Get : request.args
Post : request.form

单从客户端和服务端中任何一个其实看不出什么结果,我们整体来看,我们可以这样认为,是因为浏览器,才让这些框架去指定这样的区别,就是flask的request.argsrequest.form,然后requests库就对这样的规定妥协了,因为不管是网站服务还是api接口服务,人家已经用这样的框架,在这样的规范下写了,所以我们没有办法,也只能分个Get和Post.
这是从什么角度来看的呢,是从浏览器角度,如果绕开浏览器,我们看一下可以发现,如果客户端requests库不需要这样的规范,那么Get和Post就只有语义上的区别了,从函数看有什么区别,不都是一个url和一个参数字典.如果服务端可以保证,我的接口就只会被开发库调用,而不被浏览器访问,那写成什么样都是自己说的算,我允许Get带数据就带,允许Post在url后加东西就加东西,没任何区别.

编码

这里补充一下编码的问题,一般来说,http请求的编码需要分成url编码和body编码。

url编码在RFC中有规定,不经编码可以展示的是[a-zA-Z0-9$-_.+!*'(),],其他字符,例如中文,必须经过编码才能展示,这些需要编码的字符需要使用percent encoding来编码,编码后加到url中,但是这个编码不规定字符集,有些和浏览器相同,有些和操作系统相同,所以还是使用ajax发送请求比较好。

而body的编码就比较容易了, 可以在header中的content-type来确定。

其他

post是否需要发送两个请求

客户端行为,和协议无关

url长度

浏览器和服务器由规定,和协议无关

总结

说了这么多,想说什么呢?
Http只是协议,协议就是双方进行规范的东西,协议也是人定的,只要双方可以认同,那就没什么一定是什么样的,只不过在这个例子来看,是因为浏览器的存在,要求所有提供网站服务的人遵循这样的一个规定,然后久而久之,很多人就认为一定要这样.我们应该从广义的角度来看这些东西.如果上面的这些不能说服你,建议学习一下ES的API访问,你就知道Get请求一样可以带body.就这样.


  目录