1、Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。
2、Get将表单中数据的按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;Post是将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL。
3、Get是不安全的,因为在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。Post的所有操作对用户来说都是不可见的。
4、Get传输的数据量小,这主要是因为受URL长度限制;而Post可以传输大量的数据,所以在上传文件只能使用Post(当然还有一个原因,将在后面的提到)。
5、Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
6、Get是Form的默认方法。
# 从HTTP GET和POST的区别说起
在推特上抱怨面试时问HTTP GETE和POST的区别得到回答都不满意,有人不清楚,当时只回复了看 RFC2616。趁有空说说
面试时得到的回答大多是:POST是安全的,因为被提交的数据看不到,或者被加密的,其它的还有GET的时候中文出现乱码(在地址栏里),数据最大长度限制等等。
说 POST 比 GET 安全肯定是错的,POST跟GET都是明文传输,用httpfox等插件,或者像WireShark 等类似工具就能观察到。
POST和GET的差别其实是很大的。语义上,GET是获取指定URL上的资源,是读操作,重要的一点是不论对某个资源GET多少次,它的状态是不 会改变的,在这个意义上,我们说GET是安全的(不是被密码学或者数据保护意义上的安全)。因为GET是安全的,所以GET返回的内容可以被浏览 器,Cache服务器缓存起来(其中还有很多细节,但不影响这里的讨论)。
而POST的语意是对指定资源“追加/添加”数据,所以是不安全的,每次提交的POST,参与的代码都会认为这个操作会修改操作对象资源的状态,于是,浏览器在你按下F5的时候会跳出确认框,缓存服务器不会缓存POST请求返回内容。
很遗憾到目前为止没有应聘者能够提到这一点。我猜测这背后的原因大概有两个,一是也许大多数人往往(我也一样)满足于只要完成任务就好,不管用哪 个,表单提交了,数据处理了,内容显示或者重新定向到另外一个页面,就算完成了一个任务,从任务表里划掉,结束。而且对大部分项目(OA, CRM, MIS)的大部分情况下,用哪个似乎都可以。
同时,在被商业机构在媒体和书籍上宣传兜售的WS-*概念和使用集成开发环境提供的“方便”的代码生成工具后,“了解”到所有Web服务调用都是通 过POST,更潜意识里确定了POST和GET是一样的,而且GET能做的,POST都能做,POST简直就是GET++嘛。自然,能用POST就用 POST,不必在乎两者的差别了。
这又让我想起最近学到的一个概念: Radius Of Comprehension,理解的半径:
当学习概念A的时候,需要先了解概念B,而概念C又是理解B的前提。当B和C都是新的需要学习的概念时,可以说A的理解半径是2,如图:
A --> B --> C
|--1--|--2--|
在学习Web开发时,接触到GET和POST时,“理解的半径”可能包涵:
POST vs. GET
|---> Conditional GET -> ETag -> Cache
| `--> Status Code
`---> HTTP的方法 --> URL
往往因为仅仅满足于完成手上被要求的任务,或者懒于问一个为什么,我们就把自己的理解半径设置成零,那么就学不到更深入的东西,也因此仅仅知道POST和GET不同,而不再会了解不同在哪里,什么是Conditional GET和缓存header等概念。
从一个简单的面试问题谈到这,貌似小题大作了,写到哪算哪吧。
<UPDATE>
看到Fenng Buzz 了这篇文字,引起一些评论,因此在这再讨论两个概念: 安全的(Safe)和幂等的(Idempotent)。
安全的是指没有明显的对用户有影响的副作用(包括修改该资源的状态)。HTTP方法里的GET和HEAD都是安全的。
幂等的是指一个方法不论多少次操作,结果都是一样。PUT(把内容放到指定URL),DELETE(删除某个URL代表的资源),虽然都修改了资源内容,但多次操作,结果是相同的,因此和HEAD,GET一样都是幂等的。
所以根据HTTP协议,GET是安全的,也是幂等的,而POST既不是安全的,也不是幂等的。
</UPDATE>
HttpWebRequest 是 .net 基类库中的一个类,在命名空间 System.Net 下面,用来使用户通过 HTTP 协议和服务器交互。
HttpWebRequest 对 HTTP 协议进行了完整的封装,对 HTTP 协议中的 Header, Content, Cookie 都做了属性和方法的支持,很容易就能编写出一个模拟浏览器自动登录的程序。
程序使用 HTTP 协议和服务器交互主要是进行数据的提交,通常数据的提交是通过 GET 和 POST 两种方式来完成,下面对这两种方式进行一下说明:
1. GET 方式。 GET 方式通过在网络地址附加参数来完成数据的提交,比如在地址 http://www.google.com/webhp?hl=zh-CN 中,前面部分 http://www.google.com/webhp 表示数据提交的网址,后面部分 hl=zh-CN 表示附加的参数,其中 hl 表示一个键(key), zh-CN 表示这个键对应的值(value)。程序代码如下:
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create( "http://www.google.com/webhp?hl=zh-CN" );
req.Method = "GET";
using (WebResponse wr = req.GetResponse())
{
//在这里对接收到的页面内容进行处理
}
2. POST 方式。 POST 方式通过在页面内容中填写参数的方法来完成数据的提交,参数的格式和 GET 方式一样,是类似于 hl=zh-CN&newwindow=1 这样的结构。程序代码如下:
string param = "hl=zh-CN&newwindow=1";
byte[] bs = Encoding.ASCII.GetBytes(param);
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create( "http://www.google.com/intl/zh-CN/" );
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bs.Length;
using (Stream reqStream = req.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (WebResponse wr = req.GetResponse())
{
//在这里对接收到的页面内容进行处理
}
在上面的代码中,我们访问了 www.google.com 的网址,分别以 GET 和 POST 方式提交了数据,并接收了返回的页面内容。然而,如果提交的参数中含有中文,那么这样的处理是不够的,需要对其进行编码,让对方网站能够识别。
3. 使用 GET 方式提交中文数据。 GET 方式通过在网络地址中附加参数来完成数据提交,对于中文的编码,常用的有 gb2312 和 utf8 两种,用 gb2312 方式编码访问的程序代码如下:
Encoding myEncoding = Encoding.GetEncoding("gb2312");
string address = "http://www.baidu.com/s?" + HttpUtility.UrlEncode("参数一", myEncoding) + "=" + HttpUtility.UrlEncode("值一", myEncoding);
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(address);
req.Method = "GET";
using (WebResponse wr = req.GetResponse())
{
//在这里对接收到的页面内容进行处理
}
在上面的程序代码中,我们以 GET 方式访问了网址 http://www.baidu.com/s ,传递了参数“参数一=值一”,由于无法告知对方提交数据的编码类型,所以编码方式要以对方的网站为标准。常见的网站中, www.baidu.com (百度)的编码方式是 gb2312, www.google.com (谷歌)的编码方式是 utf8。
4. 使用 POST 方式提交中文数据。 POST 方式通过在页面内容中填写参数的方法来完成数据的提交,由于提交的参数中可以说明使用的编码方式,所以理论上能获得更大的兼容性。用 gb2312 方式编码访问的程序代码如下:
Encoding myEncoding = Encoding.GetEncoding("gb2312");
string param = HttpUtility.UrlEncode(" 参数一", myEncoding) + "=" + HttpUtility.UrlEncode("值一", myEncoding) + "& amp;" + HttpUtility.UrlEncode("参数 二", myEncoding) + "=" + HttpUtility.UrlEncode("值二", myEncoding);
byte[] postBytes = Encoding.ASCII.GetBytes(param);
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create( "http://www.baidu.com/s" );
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded;charset=gb2312";
req.ContentLength = postBytes.Length;
using (Stream reqStream = req.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (WebResponse wr = req.GetResponse())
{
//在这里对接收到的页面内容进行处理
}
从上面的代码可以看出, POST 中文数据的时候,先使用 UrlEncode 方法将中文字符转换为编码后的 ASCII 码,然后提交到服务器,提交的时候可以说明编码的方式,用来使对方服务器能够正确的解析。
以 上列出了客户端程序使用 HTTP 协议与服务器交互的情况,常用的是 GET 和 POST 方式。现在流行的 WebService 也是通 过 HTTP 协议来交互的,使用的是 POST 方法。与以上稍有所不同的是, WebService 提交的数据内容和接收到的数据内容都是使用 了 XML 方式编码。所以, HttpWebRequest 也可以使用在调用 WebService 的情况下。