基於C#的http協議開發

HTTP協議簡介

 

HTTP協議簡介

在TCP/IP體系結構中,HTTP屬於應用層協議,位於TCP/IP協議的頂層。瀏覽Web時,瀏覽器通過HTTP協議與Web服務器交換信息。這些信息(文檔)類型的格式由MIME定義。

HTTP協議具有以下的特點:

  1. HTTP按客戶/服務器模式工作
    HTTP支持客戶(一般情況是瀏覽器)與服務器的通訊,相互傳輸數據。
    HTTP定義的事務處理由以下四步組成:
    • 客戶與服務器建立連接;
    • 客戶向服務器提出請求;
    • 如果請求被接受,則服務器送回響應,在響應中包括狀態碼和所需的文件;
    • 客戶與服務器斷開連接
    一次HTTP操作稱爲一次事務transaction)。
  2. HTTP是無狀態的
    也就是說,瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,但任務結束就中斷連接。
  3. HTTP使用元信息作爲頭標
    HTTP對所有事務都加了頭標header)。也就是說,在主要數據前加上一塊信息,稱爲元信息metainformation)。它使服務器能夠提供正在傳送數據的有關信息。例如,傳送對象是哪種類型,是用哪種語言書寫的等。
    從功能上講,HTTP支持四類元信息:一般信息頭標、請求頭標、響應頭標和實體頭標。
  4. HTTP支持兩種請求和響應格式
    HTTP由不同的兩部分組成,一是從瀏覽器發往服務器的請求,二是服務器對客戶的響應。
    HTTP支持兩種請求和響應,即簡單請求與完全請求和簡單響應與完全響應。
  5. HTTP是基於文本的簡單協議

HTTP的請求

HTTP的常用請求方法:

方 法 說 明
GET 請求讀取一個Web頁面
HEAD 請求讀取一個Web頁面的頭標
PUT 請求存儲一個Web頁面
POST 附加到命名資源中
DELETE 刪除Web頁面
LINK 連接兩個已有資源
UNLINK 取消兩個資源之間的已有連接

 

HTTP請求的格式如下所示:

 <request-line>
<headers>
<blank line>
[<request-body>] 

在HTTP請求中,第一行必須是一個請求行(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)。注意,在最後一個首部之後有一個空行。即使不存在請求主體,這個空行也是必需的。

如果要獲取一個諸如XXX/xxx的XXX域內的頁面,那麼該請求可能類似於:

GET /xxx/ 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

注意只有第一行的內容發生了變化,它只包含URL中XXX後面的部分。

要發送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="[email protected]",
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="[email protected]",   ← 服務器端質詢響應信息
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(WS-Security)認證

    WSSE UsernameToken
    服務器端以nonce進行質詢,客戶端以用戶名,密碼,nonce,HTTP方法,請求的URI等信息爲基礎產生的response信息進行認證的方式。
    ※ 不包含密碼的明文傳遞
    
    WSSE認證步驟:
     1. 客戶端訪問一個受WSSE認證保護的資源。
     2. 服務器返回401狀態,要求客戶端進行認證。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: WSSE 
realm="[email protected]",
profile="UsernameToken" ← 服務器期望你用UsernameToken規則生成迴應
※ UsernameToken規則:客戶端生成一個nonce,然後根據該nonce,密碼和當前日時來算出哈希值。
     3. 客戶端將生成一個nonce值,並以該nonce值,密碼,當前日時爲基礎,算出哈希值返回給服務器。
Authorization: WSSE profile="UsernameToken"
X-WSSE:UsernameToken
username="Mufasa",
PasswordDigest="Z2Y......",
Nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
Created="2010-01-01T09:00:00Z"
     4. 如果認證成功,則返回相應的資源。如果認證失敗,則仍返回401狀態,要求重新進行認證。

    特記事項:
     1. 避免將密碼作爲明文在網絡上傳遞。
     2. 不需要在服務器端作設置。
     3. 服務器端必須保存密碼本身,否則無法進行身份驗證。
 

與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 實例。可以使用 BeginGetResponseEndGetResponse 方法對 Internet 資源發出異步請求。

當要向 Internet 資源發送數據時,GetRequestStream 方法返回用於發送數據的Stream實例。BeginGetRequestStreamEndGetRequestStream 方法提供對發送數據流的異步訪問。

下面的示例爲 URI xxx 創建 HttpWebRequest

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

HttpWebResponse類

此類包含對 WebResponse 類中的屬性和方法的 HTTP 特定用法的支持。HttpWebResponse 類用於生成發送 HTTP 請求和接收 HTTP 響應的 HTTP 獨立客戶端應用程序。

注意:不要混淆 HttpWebResponseHttpResponse;後者用於 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 資源的響應的內容。

下面的示例返回 HttpWebRequestHttpWebResponse

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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章