GET与POST请求的区别

前言

最近看了一些同行的面经,发现无论什么技术岗位,还是会问到 get 和 post 的区别,而搜索出来的答案并不能让我们装得一手好逼,那就让我们从 HTTP 报文、rfc文档角度分析分析,从而搞明白他们的区别。

标准答案

在开始之前,先来看看来自w3cshcool:get和post的区别标准答案看似很完美,但是如果照搬照抄只会适得其反。

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

注意,并不是说标准答案有误,上述区别在大部分浏览器上是普遍存在的,因为这些浏览器实现了 HTTP 标准。
所以从标准上来看,GET 和 POST 的只能做以下几种区别:

  • GET 用于获取信息,是无副作用的,是幂等的,且可缓存
  • POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存

本质区别

1.从报文角度分析

GET 和 POST 只是 HTTP 协议中两种请求方式,而 HTTP 协议是基于 TCP/IP 的应用层协议,无论 GET 还是 POST,用的都是同一个传输层协议,所以在传输上,没有区别。

报文格式上,不带参数时,最大区别就是第一行方法名不同

POST方法请求报文第一行是这样的 POST /uri HTTP/1.1 \r\n

GET方法请求报文第一行是这样的 GET /uri HTTP/1.1 \r\n

是的,不带参数时他们的区别就仅仅是报文的前几个字符不同而已

带参数时报文的区别呢? 在约定中,GET 方法的参数应该放在 url 中,POST 方法参数应该放在 body 中(注意:只是在约定中

举个小小的栗子:如果传输参数是 name=hello, sex=male。

GET 方法简约版报文报头是这样的
GET /index.php?name=hello&sex=male HTTP/1.1
Host: localhost

POST 方法简约版报文报头是这样的
POST /index.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=hello&sex=male

详细可以参照笔者认为具有比较完美说明性的文章:http://www.manongjc.com/article/7850.html

现在我们知道了两种方法本质上是 TCP 连接,没有差别,也就是说,如果我不按规范来也是可以的。我们可以在 URL 上写参数,然后方法使用 POST;也可以在 Body 写参数,然后方法使用 GET。当然,这需要服务端支持

2.从rfc文档对GET和POST请求的分析

以下是rfc文档对get和post请求的说明:

8.1 GET
GET方法就是以实体方式得到由请求URI所指定资源的信息。如果请求URI只是一个数据产生过程,那么最终要在回应实体中返回的是由该处理过程的结果所指向的资源,而不是返回该处理过程的描述文字,除非那段文字恰好是处理的输出。如果请求消息包含If-Modified-Since标题域,GET方法的语法就变成“条件GET”,即“(conditional GET)”。 条件GET方法可以对指定资源进行判断,如果它在If-Modified-Since标题域(见10.9节)中的指定日期后发生了更新,才启动传输,否则不传输。这种条件GET允许被缓存的实体在不必经过多次请求或不必要的数据传输就能进行刷新,从而有助于降低网络负载。
8.3 POST
POST方法用来向目的服务器发出请求,要求它接受被附在请求后的实体,并把它当作请求队列(Request-Line)中请求URI所指定资源的附加新子项。POST被设计成用统一的方法实现下列功能:
o 对现有资源的注释(Annotation of existing resources);
o 向电子公告栏、新闻组,邮件列表或类似讨论组发送消息;
o 提交数据块,如将表格(form [3])的结果提交给数据处理过程;
o 通过附加操作来扩展数据库。
POST方法的实际功能由服务器来决定,而且通常依赖于请求URI。在POST过程中,
实体是URI的从属部分,就好象文件从属于包含它的目录、新闻组文件从属于发出该文件
的新闻组、记录从属于其所在的数据库一样。
成功的POST不需要在原始服务器创建实体,并将其做为资源;也不需要为未来的访问提供条件。也就是说,POST方法不一定会指向URI指定的资源。在这种情况下,200(成功)或204(无内容)都是适当的回应状态,取决于实际回应实体中对结果的描述。
如果在原始服务器上创建了资源,回应应是201(已创建),并包含一个实体(对"text/html"类型最为适合),该实体中记录着对新资源请求的状态描述。
在所有的HTTP/1.0的POST请求中,必须指定合法的内容长(Content-Length)。如果HTTP/1.0服务器在接收到请求消息内容时无法确定其长度,就会返回400(非法请求)代码。应用程序不能缓存对POST请求的回应,因为做为应用程序来说,它们没有办法知道服务器在未来的请求中将如何回应。

个人观点:在rfc文档上的说法是标准,get是用来获取实体的,post是用来传递实体的。一切以遵照官方文档为准。

常见面试问题总结:

Q1:GET 方法参数写法是固定的吗?

在约定中,我们的参数是写在 ? 后面,用 & 分割。

我们知道,解析报文的过程是通过获取 TCP 数据,用正则等工具从数据中获取 Header 和 Body,从而提取参数。

也就是说,我们可以自己约定参数的写法,只要服务端能够解释出来就行(还是得服务器支持),一种比较流行的写法是 http://www.example.com/user/name/hello/sex/male。

Q2:POST 方法比 GET 方法更安全?(常问)

按照网上大部分文章的解释,POST 比 GET 安全,因为数据在地址栏上不可见。
但是从传输角度来说,它们都不安全。由于GET与POST请求都是基于http协议, 而HTTP 在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文,所以都不安全。如果想要安全传输就只能加密,比如设置cookie-session,或者使用https协议

Q3:GET 方法的长度限制是怎么回事?

在网上看到很多关于两者区别的文章都有这一条,提到浏览器地址栏输入的参数是有限的。

但是得说明一点,HTTP 协议没有 设置Body 和 URL 的长度限制,对 URL 限制的大多是浏览器和服务器的原因。

浏览器原因就不说了,由于服务器不能长时间消耗资源,为了性能和安全(防止恶意构造长 URL 来攻击、SYN攻击)考虑,会给 URL 长度加限制。

Q4:POST 方法会产生两个TCP数据包?

有些文章中提到,post 会将 header 和 body 分开发送,先发送 header,等待服务端返回 100 状态码再发送 body。首先明确等待服务器响应这一说是不存在的,body 就是紧随在 header 后面发送的

HTTP 协议中没有明确说明 POST 会产生两个 TCP 数据包,而且实际测试(Chrome)发现,header 和 body 不会分开发送。

所以,header 和 body 分开发送是部分浏览器或框架的请求方法,不属于 post 必然行为。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值