simplify the life

get与post需要注意的几点

在面试或者笔试时,经常会被问到 HTTP 方法中 get 和 post 的异同点。本文简单整理归纳了一下,以备忘。

1、"get/post" VS "web 中的 get/post"

一些 web 相关职位的面试,无论有没有提 web,面试中的 get/post,一般就是指 web 中的 get/post。需要注意的是,web 中的 get/post 只是 http 中的 get/post 的子集,所以如果谈 get 与 post 的区别,要是面试官有心挖坑,就要特别注意下你们聊的是不是 web 中的 get/post。(本文接下去讲的 get/post 基本上是基于 web 的)

关于 get/post,可以查看 rfc-2616 了解详情:

其实,http 中的 get 与 post 只是单纯的名字上的区别,get 请求的数据也可以放在 request body 中,只是浏览器没有实现它,但是 get 并不只是在 web 中使用。所以,说到 get/post 的区别,会直接条件反射地去说 web 中的 get/post 区别。而 web 中 get 以及 post,其实都可以往服务端发送数据,get 是将数据拼接在 url 上(有必要时需要 encode),而 post 是将数据封装在 request body 中,发送过去。

get/post 可以顾名思义地理解,get 是用来请求数据,那么,既然是请求数据,为什么还要带上数据呢?其实很好理解,比如一个新闻页面,有很多内页,那么 get 请求可能带上的类似这样的参数 page=1,即为请求第一页的数据。post 的话顾名思义就是发送数据,所以需要带上数据。

2、get 请求是安全和幂等的

何谓安全?这里的安全指的是在规范的定义下,get 操作不会修改服务器的数据,无论做多少次 get 请求,服务端的数据都是不会有变化的,所以说 get 请求是安全的。"get 请求是安全的" 换句话说就是 "get 请求不产生副作用",它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。

何谓幂等?幂等是说,同一个请求原封不动的发送 N 次和 M 次(N 不等于 M,N 和 M 都大于 1),服务器上资源的状态最终是一致的,相应地服务器返回的内容也是一致的。get 请求是幂等的,因为无论请求多少次,服务器上的资源状态不变,而 post 则不然,post 会更新服务器的数据。比如发贴是非幂等的,重复 10 次发贴请求会创建 10 个帖子。但修改帖子内容是幂等的,一个修改请求重复无论多少次,帖子最终状态都是一致的。

关于幂等再举个数学上的例子。对于单目运算,如果一个运算对于在范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。比如绝对值运算就是一个例子,在实数集中,有 abs(a)=abs(abs(a))。这个例子非常的好,abs(a) 可以表示做了一次 get 请求后的服务器上的资源状态,对其继续做 abs 运算,状态不变,这就好比做了一次 get 请求,继续再做,而该资源状态一直不变,所以请求得到的东西也就不会变。

因此,按照某一 ID 阅览文章就是安全而幂等的,应当使用 get。而注册用户、登录等操作会改变服务器的资源状态,不是安全而幂等的,应当使用 post。

3、post 相对 get 请求是 "安全" 的

这里的 "安全",和第二点所讲的 "安全" 又是两回事了。这里的 "安全" 是密码学上的,也就是大多数场景中 "安全" 的意思。

其实该点颇有点(post)五十步笑(get)百步之嫌。

我们知道,get 请求是将数据附在 url 上,而 post 是将数据封装在 request body 中。所以 get 请求附加的参数可能会被人在浏览器地址栏上直接看到,或者查看一下浏览器的历史记录或者日志,就能看到你的参数。而 post 因为不能被缓存,也不能被保存为书签,所以请求过了就没有记录了?请求参数就不能被截获了?非也,抓个包就可以看到了。

所以,post 请求只是相对安全的。(防君子防不了小人)

4、get 请求发送数据更小

http 协议中的 get/post 并没有发送数据大小的限制,对发送数据大小产生限制的是浏览器以及操作系统、服务器,http 本身并没有对 url 长度有所限制

IE 对 URL 长度的限制是 2083字节(<=IE 8)。对于其他浏览器,如 Netscape、FireFox 等,理论上没有长度限制,其限制取决于操作系统以及服务器的支持。而 chrome 遇到长度很长的 URL 时,会直接 崩溃

URL 长了,对服务器处理也是一种负担。原本一个会话就没有多少数据,现在如果有人恶意地构造几个几 M 大小的 URL,并不停地访问你的服务器。服务器的最大并发数显然会下降。另一种攻击方式是,把告诉服务器 Content-Length 是一个很大的数,然后只给服务器发一点儿数据,嘿嘿,服务器你就傻等着去吧。哪怕你有超时设置,这种故意的次次访问超时也能让服务器吃不了兜着走。有鉴于此,多数服务器出于安全啦、稳定啦方面的考虑,会给 URL 长度加限制。

理论上讲,POST 是没有大小限制的,HTTP 协议规范也没有进行大小限制,说 "POST数据量存在80K/100K 的大小限制" 是不准确的,POST 数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。

5、get 能被缓存,post 不能被缓存

这点非常容易理解,打开一个页面,如果之前打开过,那么很明显速度会加快,这是因为 html/js/css/img 等文件都能被浏览器缓存(也可以被服务器缓存),而这些文件的获取,都是用的 get 请求。事实上,web 中的绝大多数请求都是用 get 完成的,post 请求目前为止我只是在 ajax 以及 form 表单中有见过。

但是实际上,http 协议中 post 和 get 都是可以被缓存的,不过不要惊讶,浏览器的实现总是比标准厉害。(post 和 get 真的只有名字上的区别啊。。)

因为 get 请求会有缓存,所以在开发过程中,很多时候我们要手动清除缓存,不然看不到修改后的样子。

关于 get 请求能被缓存我有个惨痛的经历。在一次开发中,要做一个跳转页面(假设为 a.index,同时需要在主页面(假设为 index.htm)中带个参数(假设为 tmp)过去,为了方便,直接将参数附加在了跳转页面的 url 上,页面地址为 a.htm?tmp,直接取其 location.search 属性即可获取参数。之后修改了 a.htm 页面的内容,但是发现一直不生效,并且已经清除了 a.htm 页面的缓存,排查了很久,原因很显然,缓存地址为 a.htm?tmp,需要清除该地址的缓存!

所以一般要获取最新的文件(非缓存文件),可以加个类似时间戳一样的参数。

6、form 表单可以用 get 提交

form 表单有个 method 属性,一般为 "post"。但是,其实 method 属性是可以为 "get" 的,甚至,默认就是 "get"。

如果是 "post" 方式,数据藏在 request body 中,如果是 "get" 方式,数据拼接在 url 上。但是,一般 form 表示都与 "数据提交" 相辅相成,会对服务端数据做修改,所以一般都是以 "post" 的方式。

7、求他:put 以及 delete

说完 get/post,再来简单谈谈他们的其他几个好基友吧。

Http 定义了与服务器交互的不同方法,最基本的方法有 4 种,分别是 GET,POST,PUT,DELETE。URL 全称是资源描述符,我们可以这样认为:一个 URL 地址,它用于描述一个网络上的资源,而 HTTP 中的 GET,POST,PUT,DELETE 就对应着对这个资源的查,改,增,删 4 个操作。

  • GET:无副作用,幂等,不可带 Request Body
  • PUT:副作用,幂等,可以带 Request Body
  • POST:副作用,非幂等,可以带 Request Body
  • DELETE:副作用,幂等,不可带 Request Body

get 和 post 成功之后应该返回 200;而 put 和 delete 在成功时则推荐使用 202.

8、Read More

posted on 2016-03-01 22:53  lessfish  阅读(4677)  评论(13编辑  收藏  举报

导航