http请求的格式如下


<request-line>  

 <headers>  

 <blank line>  

 [<request-body>]


第一行必须是一个请求行(request line),用来说明请求类型、要访问的资源以及使用的HTTP版本。
紧接着是一个首部(header)小节,用来说明服务器要使用的附加信息。
在首部之后是一个空行。
再此之后可以添加任意的其他数据[称之为主体(body)]


在HTTP中,定义了大量的请求类型,Ajax开发人员关心的只有GET请求和POST请求。


Web浏览器上输入一个URL,浏览器就将基于该URL向服务器发送一个GET请求,以告诉服务器获取并返回什么资源。


对于URL为XXX的GET请求如下所示:

GET / HTTP/1.1  

 Host: XXX   

 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)  

 Gecko/20050225 Firefox/1.0.1  

 Connection: Keep-Alive



请求行的第一部分说明了该请求是GET请求。
该行的第二部分是一个斜杠(/),用来说明请求的是该域名的根目录。
该行的最后一部分说明使用的是HTTP 1.1版本(另一个可选项是1.0)。


第2行是请求的第一个首部,HOST。首部HOST将指出请求的目的地。
结合HOST和上一行中的斜杠(/),可以通知服务器请求的是XXX(HTTP 1.1才需要使用首部HOST,而原来的1.0版本则不需要)
第三行中包含的是首部User-Agent,服务器端和客户端脚本都能够访问它,它是浏览器类型检测逻辑的重要基础。
该信息由你使用的浏览器来定义(在本例中是Firefox 1.0.1),并且在每个请求中将自动发送。
最后一行是首部Connection,通常将浏览器操作设置为Keep-Alive)。
注意,在最后一个首部之后有一个空行。即使不存在请求主体,这个空行也是必需的。






要发送GET请求的参数,则必须将这些额外的信息附在URL本身的后面。其格式类似于:
URL ? name1=value1&name2=value2&..&nameN=valueN


该信息称之为查询字符串(query string),它将会复制在HTTP请求的请求行中,如下所示:


GET /xxx/?name=Professional%20Ajax HTTP/1.1  

 Host: XXX  

 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)  

 Gecko/20050225 Firefox/1.0.1  

 Connection: Keep-Alive



另一方面,POST请求在请求主体中为服务器提供了一些附加的信息。
通常,当填写一个在线表单并提交它时,这些填入的数据将以POST请求的方式发送给服务器。
以下就是一个典型的POST请求:

POST / HTTP/1.1  

 Host: XXX  

 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)  

 Gecko/20050225 Firefox/1.0.1  

 Content-Type: application/x-www-form-urlencoded  

 Content-Length: 40  

 Connection: Keep-Alive  

 name=Professional%20Ajax&publisher=Wiley



从上面可以发现, POST请求和GET请求之间有一些区别。
首先,请求行开始处的GET改为了POST,以表示不同的请求类型。
你会发现首部Host和User-Agent仍然存在,在后面有两个新行。
其中首部Content-Type说明了请求主体的内容是如何编码的。
浏览器始终以application/ x-www-form- urlencoded的格式编码来传送数据,这是针对简单URL编码的MIME类型。
首部Content-Length说明了请求主体的字节数。
在首部Connection后是一个空行,再后面就是请求主体。与大多数浏览器的POST请求一样,这是以简单的“名称—值”对的形式给出的
其中name是Professional Ajax,publisher是Wiley ,你可以以同样的格式来组织URL的查询字符串参数。
正如前面所提到的,还有其他的HTTP请求类型,它们遵从的基本格式与GET请求和POST请求相同。
下一步我们来看看服务器将对HTTP请求发送什么响应。




HTTP响应
如下所示,HTTP响应的格式与请求的格式十分类似:
<status-line>  
<headers>  
<blank line>  
[<response-body>]  
正如你所见,在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。
状态行(status line)通过提供一个状态码来说明所请求的资源情况。
以下就是一个HTTP响应的例子: 


HTTP/1.1 200 OK  
Date: Sat, 31 Dec 2005 23:59:59 GMT  
Content-Type: text/html;charset=ISO-8859-1  
Content-Length: 122


<html>  

 <head>  

 <title>Wrox Homepage</title>  

 </head>  

 <body>  

 <!-- body goes here -->  

 </body>  

 </html>



在本例中,状态行给出的HTTP状态代码是200,以及消息OK。
状态行始终包含的是状态码和相应的简短消息,以避免混乱。
最常用的状态码有:


200 (OK): 找到了该资源,并且一切正常。
304 (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。
401 (UNAUTHORIZED):客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器。
403 (FORBIDDEN):客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。
404 (NOT FOUND):在指定的位置不存在所申请的资源。


在状态行之后是一些首部。
通常,服务器会返回一个名为Date的首部,用来说明响应生成的日期和时间(服务器通常还会返回一些关于其自身的信息,尽管并非是必需的)。
接下来的两个首部大家应该熟悉,就是与POST请求中一样的Content-Type和Content-Length。
在本例中,首部Content-Type指定了MIME类型HTML(text/html),其编码类型是ISO-8859-1(这是针对美国英语资源的编码标准)
响应主体所包含的就是所请求资源的HTML源文件(尽管还可能包含纯文本或其他资源类型的二进制数据)。
浏览器将把这些数据显示给用户。
注意,这里并没有指明针对该响应的请求类型,不过这对于服务器并不重要。
客户端知道每种类型的请求将返回什么类型的数据,并决定如何使用这些数据。






HTTP认证


◆ 基本认证 basic authentication
客户端对于每一个realm,通过提供用户名和密码来进行认证的方式。
※  包含密码的明文传递


基本认证步骤:
    1. 客户端访问一个受http基本认证保护的资源。
    2. 服务器返回401状态,要求客户端提供用户名和密码进行认证。
       401 Unauthorized  
       WWW-Authenticate: Basic realm="WallyWorld" 
    3. 客户端将输入的用户名密码用Base64进行编码后,采用非加密的明文方式传送给服务器。
       Authorization: Basic xxxxxxxxxx. 
    4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。


特记事项:
1. Http是无状态的,同一个客户端对同一个realm内资源的每一个访问会被要求进行认证。
2. 客户端通常会缓存用户名和密码,并和authentication realm一起保存,所以,一般不需要你重新输入用户名和密码。
3. 以非加密的明文方式传输,虽然转换成了不易被人直接识别的字符串,但是无法防止用户名密码被恶意盗用。




◆ 摘要认证 digest authentication
服务器端以nonce进行质询,客户端以用户名,密码,nonce,HTTP方法,请求的URI等信息为基础产生的response信息进行认证的方式。
※ 不包含密码的明文传递


摘要认证步骤:
    1. 客户端访问一个受http摘要认证保护的资源。
    2. 服务器返回401状态以及nonce等信息,要求客户端进行认证。
       HTTP/1.1 401 Unauthorized  
       WWW-Authenticate: Digest  
       realm="testrealm@host.com",  
       qop="auth,auth-int",  
       nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  
       opaque="5ccc069c403ebaf9f0171e9517f40e41"  
    3. 客户端将以用户名,密码,nonce值,HTTP方法, 和被请求的URI为校验值基础而加密(默认为MD5算法)的摘要信息返回给服务器。
    认证必须的五个情报:
    ・ realm : 响应中包含信息
    ・ nonce : 响应中包含信息
    ・ username : 用户名
    ・ digest-uri : 请求的URI
    ・ response : 以上面四个信息加上密码信息,使用MD5算法得出的字符串。




Authorization: Digest   
username="Mufasa",  ← 客户端已知信息  
realm="testrealm@host.com",   ← 服务器端质询响应信息  
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  ← 服务器端质询响应信息  
uri="/dir/index.html", ← 客户端已知信息  
qop=auth,   ← 服务器端质询响应信息  
nc=00000001, ← 客户端计算出的信息  
cnonce="0a4f113b", ← 客户端计算出的客户端nonce  
response="6629fae49393a05397450978507c4ef1", ← 最终的摘要信息 ha3  
opaque="5ccc069c403ebaf9f0171e9517f40e41"  ← 服务器端质询响应信息


    4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。


特记事项:
     1. 避免将密码作为明文在网络上传递,相对提高了HTTP认证的安全性。
     2. 当用户为某个realm首次设置密码时,服务器保存的是以用户名,realm,密码为基础计算出的哈希值(ha1),而非密码本身。
     3. 如果qop=auth-int,在计算ha2时,除了包括HTTP方法,URI路径外,还包括请求实体主体,从而防止PUT和POST请求表示被人篡改。
     4. 但是因为nonce本身可以被用来进行摘要认证,所以也无法确保认证后传递过来的数据的安全性。


       ※ nonce:随机字符串,每次返回401响应的时候都会返回一个不同的nonce。 
       ※ nounce:随机字符串,每个请求都得到一个不同的nounce。 
       ※ MD5(Message Digest algorithm 5,信息摘要算法)
         ① 用户名:realm:密码 ⇒ ha1
         ② HTTP方法:URI ⇒ ha2
         ③ ha1:nonce:nc:cnonce:qop:ha2 ⇒ ha3


WSSE认证步骤:
     1. 客户端访问一个受WSSE认证保护的资源。
     2. 服务器返回401状态,要求客户端进行认证。
        [html] view plaincopyprint?
        HTTP/1.1 401 Unauthorized  
        WWW-Authenticate: WSSE   
        realm="testrealm@host.com",  
        profile="UsernameToken" ← 服务器期望你用UsernameToken规则生成回应  
※ UsernameToken规则:客户端生成一个nonce,然后根据该nonce,密码和当前日时来算出哈希值。
     3. 客户端将生成一个nonce值,并以该nonce值,密码,当前日时为基础,算出哈希值返回给服务器。
        [html] view plaincopyprint?
        Authorization: WSSE profile="UsernameToken"  
        X-WSSE:UsernameToken  
        username="Mufasa",  
        PasswordDigest="Z2Y......",  
        Nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  
        Created="2010-01-01T09:00:00Z"  
     4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。


特记事项:
     1. 避免将密码作为明文在网络上传递。
     2. 不需要在服务器端作设置。
     3. 服务器端必须保存密码本身,否则无法进行身份验证。


=============================================================C#  HTTP  CLASS======================================================


与HTTP相关类的简介


WebRequest类
WebRequest 是 .NET Framework 的用于访问 Internet 数据的请求/响应模型的抽象基类。
使用该请求/响应模型的应用程序可以用协议不可知的方式从 Internet 请求数据。
在这种方式下,应用程序处理 WebRequest 类的实例,而协议特定的子类则执行请求的具体细节。
请求从应用程序发送到某个特定的 URI,如服务器上的 Web 页。
URI 从一个为应用程序注册的 WebRequest 子代列表中确定要创建的适当子类。
注册 WebRequest 子代通常是为了处理某个特定的协议(如 HTTP 或 FTP),但是也可以注册它以处理对特定服务器或服务器上的路径的请求。
由于 WebRequest 类是一个抽象类,所以 WebRequest 实例在运行时的实际行为由 WebRequest.Create 方法所返回的子类确定。
注意 使用 Create 方法初始化新的 WebRequest 实例。不要使用 WebRequest 构造函数。
下面的示例说明如何创建 WebRequest 实例并返回响应。


// Initialize the WebRequest.  

 WebRequest myRequest = WebRequest.Create("xxx");  

 // Return the response.   

 WebResponse myResponse = myRequest.GetResponse();  

 // Code to use the WebResponse goes here.  

 // Close the response to free resources.  

 myResponse.Close();



WebResponse 类
WebResponse 类是抽象(在 Visual Basic 中为 MustInherit)基类,协议特定的响应类从该抽象基类派生。
应用程序可以使用 WebResponse 类的实例以协议不可知的方式参与请求和响应事务,而从 WebResponse 派生的协议特定的类携带请求的详细信息。
客户端应用程序不直接创建 WebResponse 对象,而是通过调用 WebRequest 实例上的 GetResponse 方法来创建它。
下面的示例从 WebRequest 创建 WebResponse 实例。


// Initialize the WebRequest.  

 WebRequest myRequest = WebRequest.Create("xxx");  

 // Return the response.   

 WebResponse myResponse = myRequest.GetResponse();  

 // Code to use the WebResponse goes here.  

 // Close the response to free resources.  

 myResponse.Close();



HttpWebRequest 类
HttpWebRequest 类对 WebRequest 中定义的属性和方法提供支持,也对使用户能够直接与使用 HTTP 的服务器交互的附加属性和方法提供支持。
不要使用 HttpWebRequest 构造函数。
使用 WebRequest.Create 方法初始化 HttpWebRequest 的一个新实例。
如果 URI 的方案是 http:// 或 https://,则 Create 将返回 HttpWebRequest 实例。
GetResponse 方法向 RequestUri 属性中指定的 Internet 资源发出同步请求并返回包含该响应的 HttpWebResponse 实例。
可以使用 BeginGetResponse 和 EndGetResponse 方法对 Internet 资源发出异步请求。
当要向 Internet 资源发送数据时,GetRequestStream 方法返回用于发送数据的Stream实例。
BeginGetRequestStream 和 EndGetRequestStream 方法提供对发送数据流的异步访问。
下面的示例为 URI xxx 创建 HttpWebRequest


HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("xxx");  




HttpWebResponse类
此类包含对 WebResponse 类中的属性和方法的 HTTP 特定用法的支持。
HttpWebResponse 类用于生成发送 HTTP 请求和接收 HTTP 响应的 HTTP 独立客户端应用程序。
注意:不要混淆 HttpWebResponse 和 HttpResponse;
后者用于 ASP.NET 应用程序,而且它的方法和属性是通过 ASP.NET 的内部 HttpResponse 对象公开的。
决不要直接创建 HttpWebResponse 类的实例。而应当使用通过调用 HttpWebRequest.GetResponse 所返回的实例。
从 Internet 资源返回的公共标头信息公开为该类的属性。
有关完整的列表,请参见下表。可以从 Headers 属性以名称/值对的形式读取其他标头。
下表显示可以通过 HttpWebResponse 类的属性使用的公共 HTTP 标头。


标头                 属性
Content-Encoding         ContentEncoding
Content-Length           ContentLength
Content-Type             ContentType
Last-Modified            LastModified
服务器                   Server


通过调用 GetResponseStream 方法,以 Stream 的形式返回来自 Internet 资源的响应的内容。
下面的示例返回 HttpWebRequest 的 HttpWebResponse:

HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create("xxx");  

 HttpWebResponse HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();  

 // Insert code that uses the response object.  

 HttpWResp.Close();






URI类
URI 是 Internet 上可由应用程序使用的资源的简洁表示形式。
Uri 类定义了属性和方法来处理 URI,包括分析、比较和组合。
Uri 类属性是只读的,修改 Uri 实例需使用 UriBuilder 类。
Uri 类只存储绝对 URI。相对 URI(例如“/new/index.htm”)必须相对于基 URI 展开,这样才是绝对的。
提供了 MakeRelative 方法在必要时将绝对 URI 转换为相对 URI。
URI 由转义编码存储为规范化 URI,所有 ASCII 值大于 127 的字符都被替换为它们的等效十六进制数。
为使 URI 具有规范化格式,Uri 构造函数执行以下步骤。
将 URI 方案转换为小写。
将主机名转换为小写。
移除默认端口号和空端口号。
移除多余的段(如“/”和“/test”段)以简化 URI。
使用 ToString 方法,可以将 Uri 类的内容从转义编码的 URI 引用转换为可读的 URI 引用。
一些 URI 包括段标识符或查询。段标识符是 URI 中跟在数字符号 (#) 后的任何文本,存储在 Fragment 属性中。
查询信息是 URI 中跟在问号 (?) 后的任何文本,存储在 Query 属性中。
注意:URI 类支持使用以下格式的 IP 地址:四组表示法的 IPv4 协议和冒号分隔的十六进制 IPv6 协议。
请记住在 IPv6 地址两边括上方括号,如 http://[::1]。
下面的示例创建 Uri 类的实例,并用它来创建 WebRequest。


Uri siteUri = new Uri("xxx");
WebRequest wr = WebRequest.Create(siteUri);
============================================================================================================================


WebRequest类、WebResponse 类、HttpWebRequest 类、HttpWebResponse类、URI类