通常的理解
w3schools关于这个问题的解答:HTTP方法:GET对比POST列出了一般的理解,比如:
1、GET后退按钮/刷新无害,POST数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
2、GET书签可收藏,POST为书签不可收藏。
3、GET能被缓存,POST不能缓存。
4、GET编码类型application/x-www-form-url,POST编码类型encodedapplication/x-www-form-urlencoded 或 multipart/form-data。
5、GET历史参数保留在浏览器历史中。POST参数不会保存在浏览器历史中。
6、GET对数据长度有限制,当发送数据时,GET方法向URL添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。POST无限制。
7、GET只允许ASCII字符。POST没有限制。也允许二进制数据。
8、与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET !POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
9、GET的数据在 URL 中对所有人都是可见的。POST的数据不会显示在 URL 中。
这个对比整体没什么毛病,但只是给出了一些现象上的区别,但并没有解释为什么,对于这个问题的理解不能就停在这一层。
HTTP方法的性质
RFC7231里定义了HTTP方法的几个性质:
1、Safe-安全
这里的「安全」和通常理解的「安全」意义不同,如果一个方法的语义在本质上是「只读」的,那么这个方法就是安全的。客户端向服务端的资源发起的请求如果使用了是安全的方法,就不应该引起服务端任何的状态变化,因此也是无害的。 此RFC定义,GET, HEAD, OPTIONS 和 TRACE 这几个方法是安全的。
但是这个定义只是规范,并不能保证方法的实现也是安全的,服务端的实现可能会不符合方法语义,正如上文说过的使用GET修改用户信息的情况。
引入安全这个概念的目的是为了方便网络爬虫和缓存,以免调用或者缓存某些不安全方法时引起某些意外的后果。User Agent(浏览器)应该在执行安全和不安全方法时做出区分对待,并给用户以提示。
2、Idempotent-幂等
幂等的概念是指同一个请求方法执行多次和仅执行一次的效果完全相同。按照RFC规范,PUT,DELETE和安全方法都是幂等的。同样,这也仅仅是规范,服务端实现是否幂等是无法确保的。
引入幂等主要是为了处理同一个请求重复发送的情况,比如在请求响应前失去连接,如果方法是幂等的,就可以放心地重发一次请求。这也是浏览器在后退/刷新时遇到POST会给用户提示的原因:POST语义不是幂等的,重复请求可能会带来意想不到的后果。
3、Cacheable-可缓存性
顾名思义就是一个方法是否可以被缓存,此RFC里GET,HEAD和某些情况下的POST都是可缓存的,但是绝大多数的浏览器的实现里仅仅支持GET和HEAD。关于缓存的更多内容可以去看RFC7234。
在这三个特性里一直在强调同一个事情,那就是协议不等于实现:协议规定安全在实现里不一定安全,协议规定幂等在实现里不一定幂等,协议规定可缓存在实现里不一定可缓存
总结
GET的语义是请求获取指定的资源。GET方法是安全、幂等、可缓存的(除非有 Cache-ControlHeader的约束),GET方法的报文主体没有任何语义。
POST的语义是根据请求负荷(报文主体)对指定的资源做出处理,具体的处理方式视资源类型而不同。POST不安全,不幂等,(大部分实现)不可缓存。
举一个通俗例子:在新浪微博里,GET的语义会被用在「看看我的Timeline上最新的20条微博」这样的场景,而POST的语义会被用在「发微博、评论、点赞」这样的场景中。
关于这两种方法的语义,RFC7231里原文:
The GET method requests transfer of a current selected representation for the target resource. GET is the primary mechanism of information retrieval and the focus of almost all performance optimizations. Hence, when people speak of retrieving some identifiable information via HTTP, they are generally referring to making a GET request.A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
The POST method requests that the target resource process the representation enclosed in the request according to the resource’s own specific semantics.