谈"http get和post的区别"

——以下内容如有各种问题,烦请指出,谢谢各位^_^——

最基本的Java程序员面试题都有这个题

——http get和post的区别?

不少人大学还没毕业就知道,就算不知道也会去搜,我记得我快毕业那会,简单搜出来,排在前面的大概就这么几个区别:

1、get用于获取数据,post用于提交数据

2、get提交参数追加在url后面,post参数可以通过http body提交

3、get的url会有长度上的限制,则post的数据则可以非常大

4、get提交信息明文显示在url上,不够安全,post提交的信息不会在url上显示

5、get提交可以被浏览器缓存,post不会被浏览器缓存

现在回头总结下,发现自己快毕业哪会自己真是什么都不知道啊,当时网上搜出来的这份东西就是有误的啊,国内也是各种传来传去,错误的到处看得到,都快成标准答案了。今年5月用netty http 些服务端程序时,调接口无意发现了原来get也可以使用http body提交数据,抽空弄了下tomcat,发现也可以啊。今天整理笔记看到了这里,觉得有必要在博客上记录一下,避免后来人继续犯错。

一点一点的说 第1点:rfc2616说get方法用于获取指定uri所代表的资源,应该设计成幂等的(其他情况不变时,多次请求返回同样的结果,差不多算是只读),不过在很长一段时间内,get方法都有“写”功能,最简单的例子就是/delete?id=1,然后很常见的就是jsonp形式的请求。 post方法该做什么rfc2616说是叫服务器自己决定,现实中用post进行只读操作的很多啊,一些提供http接口的数据库都有post json进行只读查询的功能,post提交表单数据进行写操作到处都是。 所以第一点这个,不怎么好评价,现在的多数用途下第一点就是废话,什么意思都没表达。不过现在RESTful炒得火热,在RESTful的理念下,第一点差不多算是对的,不过RESTful任重道远啊,比起现在只用get/post的http,毕竟实质性的功能没有多大变化。 应该是今后很长一段时间内,get和post在第一点上基本没区别,能用post实现的操作,基本上也能用get实现。

第2点:这一点是最坑的。 http没明确规定什么get/post方法要用什么样的方式传输数据,之所以出现第2点所说的情况,原因主要有两点:浏览器设计、服务器设计,浏览器不支持get+httpbody是比较常见的,fiddler模拟请求时,如果是get,你填下面的body部分会红色显示,告诉你这样不好,仅仅是不好,因为fiddler并没有禁止get+body这种请求,但看得出它不建议你用这种方式的请求。

常见的servlet服务器,比如tomcat,默认不解析get的body部分,造成了get不能用body传递参数的现象。我写了个简单的例子,对比看下就知道是tomcat没解析get的body,不是get本身不能使用body传参。

 1 import java.io.IOException;
 2
 3 import javax.servlet.http.HttpServletRequest;
 4
 5 import org.apache.commons.lang3.StringUtils;
 6 import org.springframework.stereotype.Controller;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.ResponseBody;
 9
10 @Controller
11 public class TestController {
12     private static final String NEW_LINE = StringUtils.CR + StringUtils.LF;
13
14     @ResponseBody
15     @RequestMapping("/testLogin")
16     public String testLogin(HttpServletRequest req, String username, String pwd) throws IOException {
17         StringBuilder builder = new StringBuilder();
18         builder.append("req.method: ").append(req.getMethod()).append(NEW_LINE);
19         builder.append("req.queryString: ").append(req.getQueryString()).append(NEW_LINE);
20         int contentLength = req.getContentLength();
21         String body = null;
22         if (contentLength > 0) {
23             byte[] bytes = new byte[contentLength];
24             req.getInputStream().read(bytes);
25             body = new String(bytes, "UTF-8");
26         }
27         builder.append("req.body: ").append(body).append(NEW_LINE);
28         builder.append("req.params.username: ").append(req.getParameter("username")).append(NEW_LINE);
29         builder.append("req.params.pwd: ").append(req.getParameter("pwd")).append(NEW_LINE);
30         builder.append("username: ").append(username).append(NEW_LINE);
31         builder.append("pwd: ").append(pwd);
32         System.err.println(builder);
33         return builder.toString();
34     }
35 }

上面这个controller功能很简单,就是打印请求参数,并且原样返回,结果如下

上面张图看出来,body部分可以获取得到,但是tomcat没有读取了ServletInputStream中的body并解析body,造成req.getParam获取不到对应的参数。

这张图就是把方法换成POST,Request的其余一个字符都没有变,可以看到tomcat读取了ServletInputStream中的body,并进行解析,造成了手动读取ServletInputStream时流中没有内容了,打印出来的req.body显示无内容,req.getParam能够获取到解析完成后对应的参数。

这张图是普通的get+queryString,效果和post+body一样。

对比上面三个结果就知道,get不是不能使用body传参,只是浏览器和服务器进行了限制。浏览器的限制我不知道,这个研究得不多,tomcat的限制倒是可以根据配置解除。

官方配置:http://tomcat.apache.org/tomcat-8.0-doc/config/http.html

具体就是这一项

默认是POST,也就是当Content-Type=application/x-www-form-urlencoded(提交Web表单时的标准数据传输格式,跟url传参格式一样,使用键值对,用&区分)时,只对post方法的body部分进行解析。把tomcat的server.xml中Http1.1的Connector配置上这项,就能够让tomcat能够解析get的body部分,也就能够在tomcat上使用get+body的方式了。

上面这图是修改配置后的结果,改完配置后get+body跟post+body功能一样了。

第3点:这个跟第2点一样,rfc2616中说了不对uri长度做限制,要求http能够实现无限长度的uri,无限长度的body。

原话是下面这个:

The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).

Note: Servers ought to be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations might not properly support these lengths.

rfc2616:http://www.ietf.org/rfc/rfc2616.txt

现实中就是太长的url没什么用,太长的body部分也不是很好,所以各种客户端服务端的实现默认都有限制的这http种各个部分的长度。浏览器的我不清楚,服务端的http实现一般这个长度都是可以配置的,netty http的HttpServerCodec默认是4K长度(整个请求行,uri是请求行里面大头),tomcat是用maxHttpHeaderSize来配置请求行和header部分的总长度;post长度,netty http默认是8K,tomcat默认是maxPostSize=2M,tomcat的配置设置成-1就是无限长度,但是这么做在实际中一点意义没有。

第4点:安全,这个扯得有点远,也随便扯扯。 不是别人一眼看不到的就是安全,不是别人一眼看得到就不安全。http抓包很容易的,对路由器做点手脚就能够抓一堆移动设备的http请求包,移动设备的http请求你自己都一眼看不到,更不用说别人了,想要安全,还是用https吧,大多数人看到了也没用。

另外扯一句,Base64不是加密,用这个加密就是掩耳盗铃啊。

第5点:关于http response的缓存

get被建议做成幂等的,缓存是很有必要的,一般静态资源的get请求都是会设置有效缓存时间的,这一点很容易想明白。很多时候缓存get在服务器和浏览器中是默认行为,这对大量使用get请求的ajax不利,所以ajax请求一般会在请求url后加上一个随机数,浏览器和服务器就认为它是不同的get请求,不会缓存这个get请求。

关于post的缓存,现在的实际情况是绝大多数浏览器都不支持post缓存,但是rfc2616中关于post的response是否缓存说得很混乱,主要有两个地方说了post的缓存。

第一个是关于post方法的说明中(9.5小节):

Responses to this method are not cacheable, unless the response includes appropriate Cache-Control or Expires header fields. However, the 303 (See Other) response can be used to direct the user agent to retrieve a cacheable resource.

这段话也就是说,是否缓存post的response,是根据http请求头中的Cache-Control、Expires决定的。

还有一个位置,13.10小节(13节是专门说缓存的):

In this section, the phrase "invalidate an entity" means that the cache will either remove all instances of that entity from its storage, or will mark these as "invalid" and in need of a mandatory revalidation before they can be returned in response to a subsequent request.

Some HTTP methods MUST cause a cache to invalidate an entity. This is either the entity referred to by the Request-URI, or by the Location or Content-Location headers (if present).

These methods are:

- PUT

- DELETE

- POST

这段话是说 PUT DELETE POST 应该让缓存无效uri代表的实体——删除该实体的所有实例存储,或将这些标记为“无效”并需要强制性重新验证,然后才能返回以响应后续操作请求。

我觉得这两处规定有冲突啊,都说叫POST无效缓存,那还缓存毛线啊!

stackoverflow上有个问题讨论这个,感觉也没说明白:http://stackoverflow.com/questions/626057/is-it-possible-to-cache-post-methods-in-http

所以呢,这个post的缓存有待继续确认下,或者哪位大牛点明下,我个人暂时还是不太明白rfc2616真正想说的是什么。

总结:工作也有些时间了,我也不是一个纯小白了,了解了一些方法和途径,该多靠自己的力量去弄懂些东西。还有,这个问题一路走来也是深有感触啊,网上搜到的东西不一定正确,排名靠前的也不一定是最真的,但确是那些初学者最能依赖的。像我这种工作的时候自己捣鼓无意间发现的还算幸运啊,毕竟这个问题,对于很多人,毕业的时候就定型了,可能会一辈子错下去。

——以上内容如有各种问题,烦请指出,谢谢各位^_^——

时间: 2024-10-09 01:25:00

谈"http get和post的区别"的相关文章

浅谈Its与It's的区别

浅谈Its与It's的区别 http://www.hjenglish.com/new/p103924/ 旅英多年的作家陶杰先生在其专栏谈居英期间的见闻,说英国很多大学生连its和it's也分不清楚.大家会不会也分不清楚啊?请先拿纸笔出来,用its和it's各造一个句子看看.造了句子才继续看下去好吗? Its是代词,也是it的所有格(genitive case),解作“它的”. It's则是it is或it has的缩略语. 以下两句,请在虚线上填写正确的字: _____ time to buy

宝付谈都是程序员为啥区别这么大

宝付谈都是程序员为啥区别这么大.现下程序员受到了很多网友的关注,他们的工作制度频频上了微博热搜,很多互联网的大佬纷纷谈起了对他们工作制的看法,一位大佬甚至放出了"996"能够给大家福报,而另一位大佬则称自己在年轻的时候还能够"8116+2".宝付获悉近日一名程序员就在网上晒出了自己的年终奖,很多网友看后都不淡定了. 这名网友称自己是在北京的一家大型互联网公司当程序员,如今已经工作了三年,薪资也逐渐稳定下来,在公司他的业绩还算不错,经常能够和老板一起出去外面吃饭,但是

(进阶篇)浅谈COOKIE和SESSION关系和区别

COOKIE介绍 cookie 常用于识别用户.cookie 是服务器留在用户计算机中的小文件.每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie.通过 PHP,您能够创建并取回 cookie 的值. 1.设置Cookie PHP用SetCookie函数来设置Cookie. SetCookie函数定义了一个Cookie,并且把它附加在HTTP头的后面,SetCookie函数的原型如下: int SetCookie(string name, string value, int exp

浅谈Java接口和抽象类的区别

面向对象的设计,服用的重点其实应该是抽象层的复用,而不是具体某一个代码块的复用. 说到了抽象,就不得不提到Java接口和Java抽象类了,这也是我这里想要谈论的重点. Java接口和抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现.OOP面向对象编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口编程,面向抽象编程,正确地使用接口,抽象类这些有用的抽象类型作为你结构层次上的顶层. Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方

浅谈关于SRAM与DRAM的区别

在上体系结构这门课之前,我只知道DRAM用作内存比较多,SRAM用作cache比较多.在今天讲到内存技术时,我对于这两个基础概念有了更加完整的认识.这篇文章是我的听课心得,现在分享给各位,仅供参考,若有错误多多指正. 从名字上看,SRAM与DRAM的区别只在于一个是静态一个是动态.由于SRAM不需要刷新电路就能够保存数据,所以具有静止存取数据的作用.而DRAM则需要不停地刷新电路,否则内部的数据将会消失.而且不停刷新电路的功耗是很高的,在我们的PC待机时消耗的电量有很大一部分都来自于对内存的刷新

浅谈 Mybatis中的 ${ } 和 #{ }的区别

一.举例说明 1 select * from user where name = "dato"; 2 3 select * from user where name = #{name}; 4 5 select * from user where name = ${name}; 一般情况下,我们都不会注意到这里面有什么不一样的地方.因为这些sql都可以达到我们的目的,去查询名字叫dato的用户. 二.区别 动态 SQL 是 mybatis 的强大特性之一,也是它优于其他 ORM 框架的一

浅谈mysql和sql server的区别

对于程序开发人员而言,目前使用最流行的两种后台数据库即为MySQL and SQL Server.这两者最基本的相似之处在于数据存储和属于查询系统.你可以使用SQL来访问这两种数据库的数据,因为它们都支持ANSI-SQL.还有,这两种数据库系统都支持二进制关键词和关键索引,这就大大地加快了查询速度.同时,二者也都提供支持XML的各种格式.除了在显而易见的软件价格上的区别之外,这两个产品还有什么明显的区别吗?在这二者之间你是如何选择的?让我们看看这两个产品的主要的不同之处,包括发行费用,性能以及它

浅谈session,cookie,sessionStorage,localStorage的区别及应用场景

浏览器的缓存机制提供了可以将用户数据存储在客户端上的方式,可以利用cookie,session等跟服务端进行数据交互. 一.cookie和session cookie和session都是用来跟踪浏览器用户身份的会话方式. 区别: 1.保持状态:cookie保存在浏览器端,session保存在服务器端 2.使用方式: (1)cookie机制:如果不在浏览器中设置过期时间,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称会话cookie.如果在浏览器中设置了cookie

浅谈:html5和html的区别

什么是html5呢? html5最先由WHATWG(Web 超文本应用技术工作组)命名的一种超文本标记语言,随后和W3C的xhtml2.0(标准)相结合,产生现在最新一代的超文本标记语言.可以简单点理解成:HTML 5 ≍ HTML+CSS 3+JS+API. hmtl5于html的区别 我们现在web前端开发的静态网页,一般都是html4.0.同时是符合W3C的xhtml1.0规范来的.那么他们两者又有什么实质性的区别呢? 1.在文档类型声明上 html:<!DOCTYPE html PUBL