HTTP协议我想任何IT人士都耳熟能详了,大家都能说出个所以然来。但是如果我问你HTTP协议的请求方法有哪些?POST与GET的差异?GET或POST传送数据量的大小有限制吗?HTTP响应的状态有哪些?以及在C#中你如何使用?如果你不能清楚地回答其中的大部分问题,那么这篇文章就是为你准备的!大纲如下:
1、HTTP概述
1.1、HTTP协议的客户端与服务器的交互
1.2、HTTP消息
1.3、HTTP请求的方法
1.4、HTTP响应的代码
2、抓包分析
3、POST与GET的差异
4、以一个实例说明C#中如何使用POST、GET等操作
4.1、HttpWebRequest
4.2、HttpWebResponse
4.3、编写WinForm程序打开博客园首页(附源码)
通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端发送过来的请求。一旦收到请求,服务器(向客户端)发回一个状态行,比如"HTTP/1.1 200 OK",和(响应的)消息,消息的消息体可能是请求的文件、错误消息、或者其它一些信息。
客户端与服务器端的结构与交互过程可以表示为下面2张图:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/093827242.png"></a>
图1、Web客户端-服务器端结构(其中web服务器的超文本链接,即通过网站上的一个链接跳转到了其他服务器上)
<a target="_blank" href="http://blog.51cto.com/attachment/201008/093919680.png"></a>
图2、Web客户端与服务器端的交互
客户端与服务器之间的交互用到了两种类型的消息:请求(Request)和响应(Response)。
HTTP请求的格式为:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094004763.jpg"></a>
图3、HTTP请求的格式
HTTP响应的格式为:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094034574.jpg"></a>
图4、HTTP响应的格式
从上面可以看出HTTP的请求和响应消息的首部均包含可变数量的字段,用一个空行(blank line)将所有首部字段(header)与消息主体(body)分隔开来。一个首部字段由字段名和随后的冒号、一个空格和字段值组成,字段名不区分大小写。
报文头可分为三类:一类应用于请求,一类应用于响应,还有一类描述主体。有一些报文头(例如:Date)既可用于请求又可用于响应。描述主体的报文头可以出现在POST请求和所有响应报文中。HTTP的首部字段如下图所示:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094117135.png"></a>
图5、HTTP首部字段
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”)来表明Request-URI指定的资源的不同操作方式:
OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。
HEAD
向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
GET
POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT
向指定资源位置上传其最新内容。
DELETE
请求服务器删除Request-URI所标识的资源。
TRACE
回显服务器收到的请求,主要用于测试或诊断。
CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed);当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。
HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。
安全方法 但是,不能想当然地认为服务器不会在处理某个GET请求时不会产生任何副作用。事实上,很多动态资源会把这作为其特性。这里重要的区别在于用户并没有请求这一副作用,因此不应由用户为这些副作用承担责任。 幂等方法 假如在不考虑诸如错误或者过期等问题的情况下,若干次请求的副作用与单次请求相同或者根本没有副作用,那么这些请求方法就能够被视作“幂等”的。GET,HEAD,PUT和DELETE方法都有这样的幂等属性,同样由于根据协议,OPTIONS,TRACE都不应有副作用,因此也理所当然也是幂等的。 假如某个由若干个请求做成的请求串行产生的结果在重复执行这个请求串行或者其中任何一个或多个请求后仍没有发生变化,则这个请求串行便是“幂等” 的。但是,可能出现若干个请求做成的请求串行是“非幂等”的,即使这个请求串行中所有执行的请求方法都是幂等的。例如,这个请求串行的结果依赖于某个会在下次执行这个串行的过程中被修改的变量。
服务器程序响应的第一行叫状态行。状态行以HTTP版本号开始,后面跟着3位数字表示响应代码,最后是易读的响应短语。根据第一位可以把响应分成5类:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094302267.png"></a>
图6、HTTP响应代码
现在我们对HTTP基本上算是了解了,下面我用wireshark抓取打开博客园首页时,我的电脑与博客园服务器的交互过程的HTTP数据包。做好准备工作,关闭一些可能干扰我们抓取打开博客园的相关程序。如下图,我们在浏览器中输入www.cnblogs.com并确定时,首先抓到如下包:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094457789.png"></a>
图7、打开博客园抓取的包
从图中可以看出,我们在浏览器中输入www.cnblogs.com并确定时是向服务器发送了一个HTTP请求消息:GET / HTTP/1.1。根据1.2中介绍的HTTP消息的格式,我们知道GET对应request、/对应request-line、HTTP/1.1对应版本号。除了请求行之外,发送了一些首部字段,如:Accept、Accept-Language、User-Agent、Accept-Encoding、Host、Connection等。而且可以看出他们的格式就是:首部字段名: 字段值,注意冒号后面有个空格。
接下来我们看一下GET / HTTP/1.1请求的响应消息是怎样的:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094548643.png"></a>
图8、GET / HTTP/1.1请求的响应消息
响应消息的状态行是:HTTP/1.1 200 OK,其中HTTP/1.1对应版本号、200对应response-code、OK对应response-phrase。除了状态行,还返回了一些首部字段,如:Cache-Control、Content-Type、Content-Encoding、Expires、Last-Modified、Vary、Server等等。(通过上图我们可以看出,博客用的是IIS7.0)
上面抓的是GET的数据包,现在我来看一个POST的数据包——打开博客园首页过程中获取左边的分类信息就是通过POST请求返回的。
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094649143.png"></a>
图9、POST数据包
我们可以看到,POST /ws/PublicUserService.asmx/GetLoginInfo HTTP/1.1。除了把GET换成了POST之外,其它信息差不多。下面我们放大看下发送的首部字段:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094723692.png"></a>
图10、POST /ws/PublicUserService.asmx/GetLoginInfo HTTP/1.1的首部字段
NOTE:本节涉及的一些首部字段我就不在这里解释了。我想,到了这里大家对HTTP的认识应该更深入了一步。
1.3中介绍了8种方法,其中GET与POST最基本和常用了。表单提交中get和post方式的区别归纳如下几点:
GET是从服务器上获取数据,POST是向服务器传送数据。
GET是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。POST是通过HTTP POST机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
对于GET方式,服务器端用Request.QueryString获取变量的值,对于POST方式,服务器端用Request.Form获取提交的数据。
GET传送的数据量较小,不能大于2KB(这主要是因为受URL长度限制)。POST传送的数据量较大,一般被默认为不受限制。但理论上,限制取决于服务器的处理能力。
GET安全性较低,POST安全性较高。因为GET在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。POST的所有操作对用户来说都是不可见的。
在FORM提交的时候,如果不指定Method,则默认为GET请求(.net默认是POST),Form中提交的数据将会附加在url之后,以?分开与url分开。字母数字字符原样发送,但空格转换为“+”号,其它符号转换为%XX,其中XX为该符号以16进制表示的ASCII(或ISO Latin-1)值。GET请求请提交的数据放置在HTTP请求协议头中,而POST提交的数据则放在实体数据中;GET方式提交的数据最多只能有2048字节,而POST则没有此限制。POST传递的参数在doc里,也就http协议所传递的文本,接受时再解析参数部分。获得参数。一般用POST比较好。POST提交数据是隐式的,GET是通过在url里面传递的,用来传递一些不需要保密的数据,GET是通过在URL里传递参数,POST不是。
说明:关于“POST与GET的差异”查考了网上前辈的资料,由于找不出源头,到处都是转帖,这里就不贴出相关网址了,baidu或Google下就知道了。
在介绍实例之前,我们要先介绍一下HttpWebRequest和HttpWebResponse,在C#中就是用这两个类实现客户端向服务器端发送HTTP消息、客户端接受服务器端的HTTP响应。
HTTP消息的首部字段(headers),在HttpWebRequest中表示为公开的属性。下表列出了由属性或方法设置或由系统设置的 HTTP 标头。
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094823552.png"></a>
如果本地计算机配置指定使用代理,或者如果请求指定代理,则使用代理发送请求。如果未指定代理,则请求发送到服务器。
HttpWebRequest类主要包括如下方法,用于与HTTP服务器交互:
注意
<a target="_blank" href="http://blog.51cto.com/attachment/201008/094931759.png"></a>
HttpWebRequest类主要包括如下方法与HTTP服务器交互:(与HttpWebRequest类相比,方法较少)
通过前面两小节的介绍,我们对HttpWebRequest类和HttpWebRequest类有所了解,现在我们就应用它们来编写一个小程序来实践。程序界面大概如下:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/095015356.png"></a>
功能也比较简单,就是通过点击“在WebBrowser中显示”按钮就在下方的 WebBrowser控件中显示博客园首页,通过点击查看“html源码”按钮就弹出一个对话框显示博客园首页的html源码。
首先我们介绍如何实现——通过点击查看“html源码”按钮就弹出一个对话框显示博客园首页的html源码。核心代码如下:
private string GetCnBlogs()
{
string html = String.Empty;
HttpWebRequest cnbogs = (HttpWebRequest)System.Net.WebRequest.Create(txtURL.Text.ToString());
cnbogs.Accept = "image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/QVOD, application/QVOD, */*";
cnbogs.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MALN; CIBA; InfoPath.2; .NET4.0C; .NET4.0E; Media Center PC 6.0; Tablet PC 2.0; AskTB5.6)";
cnbogs.Method = "GET";
HttpWebResponse cnblogsRespone = (HttpWebResponse)cnbogs.GetResponse();
if (cnblogsRespone != null&&cnblogsRespone.StatusCode==HttpStatusCode.OK)
{
using(StreamReader sr = new StreamReader(cnblogsRespone.GetResponseStream()))
{
html = sr.ReadToEnd();
}
}
return html;
}
private void btnGetHtml_Click(object sender, EventArgs e)
MessageBox.Show(GetCnBlogs());
}
其实这个过程更我们通过在浏览器中输入博客园网站打开效果是一样的,只不过在这里我们是通过HttpWebRequest类和HttpWebRequest类的对象来实现的。
我这个源码还是比较简陋,只是简单地实现了使用HttpWebRequest类和HttpWebRequest类与HTTP服务器交互,更完善的功能期待你去完成。
参考:写此文章时,我参阅了不少文章,我列举其中印象比较深的
TCP/IP协议详解卷3
本文转自Saylor87 51CTO博客,原文链接:http://blog.51cto.com/skynet/366055,如需转载请自行联系原作者