乐趣区

get和post两种请求方法的区别

最直观的区别就是 GET 把参数包含在 URL 中,POST 通过 request body 传递参数。语义上的区别,get 用于获取数据,post 用于提交数据。get 参数有长度限制(受限于 url 长度,具体的数值取决于浏览器和服务器的限制),而 post 无限制
基于 HTTP 协议上解释如下:
w3schools 关于这个问题的解答:
GET 后退按钮 / 刷新无害,POST 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。GET 书签可收藏,POST 为书签不可收藏。GET 能被缓存,POST 不能缓存。GET 编码类型 application/x-www-form-url,POST 编码类型 encodedapplication/x-www-form-urlencoded 或 multipart/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 中。
参数大小的限制是怎么回事:HTTP 协议对 GET 和 POST 都没有对长度的限制,HTTP 协议明确地指出了,HTTP 头和 Body 都没有长度的要求。而对于 URL 长度上的限制,有两方面的原因造成:(1)、(大多数)浏览器通常都会限制 url 长度在 2K 个字节(2)、(大多数)服务器最多处理 64K 大小的 url。URL 长了,对服务器处理也是一种负担。原本一个会话就没有多少数据,现在如果有人恶意地构造几个几 M 大小的 URL,并不停地访问你的服务器。服务器的最大并发数显然会下降。另一种攻击方式是,把告诉服务器 Content-Length 是一个很大的数,然后只给服务器发一点儿数据,嘿嘿,服务器你就傻等着去吧。哪怕你有超时设置,这种故意的次次访问超时也能让服务器吃不了兜着走。有鉴于此,多数服务器出于安全啦、稳定啦方面的考虑,会给 URL 长度加限制。但是这个限制是针对所有 HTTP 请求的,与 GET、POST 没有关系。安全不安全和 GET、POST 没有关系
其实这些只是一些现象上的区别,如果深入了解,GET 和 POST 本质上没有区别的
基于 TCP 协议上解释如下:
1、现代的 Web Server 都是支持 GET 中包含 BODY 这样的请求。虽然这种请求不可能从浏览器发出,但是现在的 Web Server 又不是只给浏览器用,已经完全地超出了 HTML 服务器的范畴了。
2、HTTP 的底层是 TCP/IP。所以 GET 和 POST 的底层也是 TCP/IP,也就是说,GET/POST 都是 TCP 链接。GET 和 POST 能做的事情是一样一样的。你要给 GET 加上 request body,给 POST 带上 url 参数,技术上是完全行的通的。
3、GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包。对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据);而对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。这里有段引用:

因为 POST 需要两步,时间上消耗的要多一点,看起来 GET 比 POST 更有效。因此 Yahoo 团队有推荐用 GET 替换 POST 来优化网站性能。但这是一个坑!跳入需谨慎。为什么?

GET 与 POST 都有自己的语义,不能随便混用。
据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的 TCP 在验证数据包完整性上,有非常大的优点。
并不是所有浏览器都会在 POST 中发送两次包,Firefox 就只发送一次。

此处引用另一个解释:
首先强调下:协议不等于实现:协议规定安全在实现里不一定安全,协议规定幂等在实现里不一定幂等,协议规定可缓存在实现里不一定可缓存。
我们通常在讨论 GET vs POST 的时候,实际上讨论的是 specification,而不是 implementation。什么是 specification?说白了就是相关的 RFC。implementation 则是所有实现了 specification 中描述的代码 / 库 / 产品,比如 curl,Python 的 requests 库,或者 Chrome。POST 请求怎么发送,根本就不是这段 RFC 在讨论的事情。RFC 中只说明了 100 continue 和 Expect header 的联系,比如你想在 GET 请求里带 body,一样可以发送 Expect: 100-continue 并等待 100 continue,这是符合标准的。也就是说,『XHR 发送两个 TCP packets』是关于 implementation 的知识,而不是关于 specification 的知识。你不能说『Chrome 在 AJAX POST 的时候会发两个 TCP packets,GET 只会发一个』是 GET 和 POST 的区别,正如你不能因为北京 PM 2.5 经常爆表就说国家关于工业废气排放的标准有问题。
什么是 RFC 呢?

征求意见稿(英语:Request For Comments,缩写为 RFC),是由互联网工程任务组(IETF)发布的一系列备忘录。文件收集了有关互联网相关信息,以及 UNIX 和互联网社区的软件文件,以编号排定。目前 RFC 文件是由互联网协会(ISOC)赞助发行。简单理解 RFC 就是互联网的规范,我们通常所说的「协议」就是以 RFC 的形式存在,而现行的 HTTP/1.1 规范的 RFC 有如下几个:RFC7230,RFC7231,RFC7232,RFC7233,RFC7234,RFC7235。其中 RFC7231 里的 Section 4. Request Methods 涉及到了几个 HTTP 方法,接下来仔细阅读这一章节。The request method token is the primary source of request semantics; it indicates the purpose for which the client has made this request and what is expected by the client as a successful result.
这里牵涉到一个很重要的词语:semantic「语义」,那么什么是语义呢?这一篇文章给出了解释:语法和语义的区别。
一种语言是合法句子的集合。什么样的句子是合法的呢?可以从两方面来判断:语法和语义。语法是和文法结构有关,然而语义是和按照这个结构所组合的单词符号的意义有关。合理的语法结构并不表明语义是合法的。例如我们常说:我上大学,这个句子是符合语法规则的,也符合语义规则。但是大学上我,虽然符合语法规则,但没有什么意义,所以说是不符合语义的。
对于 HTTP 请求来说,语法是指请求响应的格式,比如请求第一行必须是 方法名 URI 协议 / 版本 这样的格式,
语义则定义了这一类型的请求具有什么样的性质。比如 GET 的语义就是「获取资源」,POST 的语义是「处理资源」,那么在具体实现这两个方法时,就必须考虑其语义,做出符合其语义的行为。
当然在符合语法的前提下实现违背语义的行为也是可以做到的,比如使用 GET 方法修改用户信息,POST 获取资源列表,这样就只能说这个请求是「合法」的,但不是「符合语义」的。写到这里突然联想到 XML 里面的两个概念:Well Formed 和 Valid,似乎也正是语法和语义的理念呢。
上文说到方法是请求语义的主要来源,也即是还有次要来源,一些请求 Header 可以进一步修饰请求的语义,比如一个带上了 Range Header 的 GET 请求就变成了部分请求。
RFC7231 里定义了 HTTP 方法的几个性质:

Safe – 安全。这里的「安全」和通常理解的「安全」意义不同,如果一个方法的语义在本质上是「只读」的,那么这个方法就是安全的。客户端向服务端的资源发起的请求如果使用了是安全的方法,就不应该引起服务端任何的状态变化,因此也是无害的。此 RFC 定义,GET, HEAD, OPTIONS 和 TRACE 这几个方法是安全的。但是这个定义只是规范,并不能保证方法的实现也是安全的,服务端的实现可能会不符合方法语义,正如上文说过的使用 GET 修改用户信息的情况。引入安全这个概念的目的是为了方便网络爬虫和缓存,以免调用或者缓存某些不安全方法时引起某些意外的后果。User Agent(浏览器)应该在执行安全和不安全方法时做出区分对待,并给用户以提示。
Idempotent – 幂等幂等的概念是指同一个请求方法执行多次和仅执行一次的效果完全相同。按照 RFC 规范,PUT,DELETE 和安全方法都是幂等的。同样,这也仅仅是规范,服务端实现是否幂等是无法确保的。引入幂等主要是为了处理同一个请求重复发送的情况,比如在请求响应前失去连接,如果方法是幂等的,就可以放心地重发一次请求。这也是浏览器在后退 / 刷新时遇到 POST 会给用户提示的原因:POST 语义不是幂等的,重复请求可能会带来意想不到的后果。
Cacheable – 可缓存性 顾名思义就是一个方法是否可以被缓存,此 RFC 里 GET,HEAD 和某些情况下的 POST 都是可缓存的,但是绝大多数的浏览器的实现里仅仅支持 GET 和 HEAD。关于缓存的更多内容可以去看 RFC7234。

在这三个特性里一直在强调同一个事情,那就是协议不等于实现:协议规定安全在实现里不一定安全,协议规定幂等在实现里不一定幂等,协议规定可缓存在实现里不一定可缓存。这其实就是上面那个作者提到的 specification 和 implementation 的关系。
走到这一步,其实就明白了要理解这两个方法的区别,本质上是「语义」的对比而不是「语法」的对比,是「Specification」的对比而不是「Implementation」的对比。

退出移动版