HTTP協議及其POST與GET操作差異 & C#中如何使用POST、GET等
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程式開啟部落格園首頁(附原始碼)
1、HTTP概述
為了喚醒你對HTTP協議的記憶或使你能夠對HTTP協議有所瞭解,首先簡單一下HTTP協議。超文字傳輸協議(HTTP,HyperText Transfer Protocol)是網際網路上應用最為廣泛的一種網路協議。所有的WWW檔案都必須遵守這個標準。設計HTTP最初的目的是為了提供一種釋出和接收HTML頁面的方法。
HTTP的發展是全球資訊網協會(World Wide Web Consortium)和Internet工作小組(Internet Engineering Task Force
1.1、HTTP協議的客戶端與伺服器的互動
HTTP是一個客戶端和伺服器端請求和應答的標準(TCP)。客戶端是終端使用者,伺服器端是網站。通過使用Web瀏覽器、網路爬蟲或者其它的工具,客戶端發起一個到伺服器上指定埠(預設埠為80)的HTTP請求。(我們稱這個客戶端)呼叫戶代理(user agent)。應答的伺服器上儲存著(一些)資源,比如HTML檔案和影象。(我們稱)這個應答伺服器為源伺服器(origin server)。在使用者代理和源伺服器中間可能存在多箇中間層,比如代理,閘道器,或者隧道(tunnel)。儘管
通常,由HTTP客戶端發起一個請求,建立一個到伺服器指定埠(預設是80埠)的TCP連線。HTTP伺服器則在那個埠監聽客戶端傳送過來的請求。一旦收到請求,伺服器(向客戶端)發回一個狀態行,比如"HTTP/1.1 200 OK",和(響應的)訊息,訊息的訊息體可能是請求的檔案、錯誤訊息、或者其它一些資訊。
HTTP使用TCP而不是UDP的原因在於(開啟一個)一個網頁必須傳送很多資料,而TCP協議提供傳輸控制,按順序組織資料,和錯誤糾正。通過HTTP或者HTTPS協議請求的資源由統一資源識別符號(Uniform Resource Identifiers,或者,更準確一些,URI)來標識。
客戶端與伺服器端的結構與互動過程可以表示為下面2張圖:
圖1、Web客戶端-伺服器端結構(其中web伺服器的超文字連結,即通過網站上的一個連結跳轉到了其他伺服器上)
1.2、HTTP訊息
客戶端與伺服器之間的互動用到了兩種型別的訊息:請求(Request)和響應(Response)。
HTTP請求的格式為:
圖3、HTTP請求的格式
HTTP響應的格式為:
圖4、HTTP響應的格式
從上面可以看出HTTP的請求和響應訊息的首部均包含可變數量的欄位,用一個空行(blank line)將所有首部欄位(header)與訊息主體(body)分隔開來。一個首部欄位由欄位名和隨後的冒號、一個空格和欄位值組成,欄位名不區分大小寫。
報文頭可分為三類:一類應用於請求,一類應用於響應,還有一類描述主體。有一些報文頭(例如:Date)既可用於請求又可用於響應。描述主體的報文頭可以出現在POST請求和所有響應報文中。HTTP的首部欄位如下圖所示:
圖5、HTTP首部欄位
1.3、HTTP請求的方法
HTTP/1.1協議中共定義了八種方法(有時也叫“動作”)來表明Request-URI指定的資源的不同操作方式:
- OPTIONS
返回伺服器針對特定資源所支援的HTTP請求方法。也可以利用向Web伺服器傳送'*'的請求來測試伺服器的功能性。 - HEAD
向伺服器索要與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應訊息頭中的元資訊。 - GET
向特定的資源發出請求。注意:GET方法不應當被用於產生“副作用”的操作中,例如在Web Application中。其中一個原因是GET可能會被網路蜘蛛等隨意訪問。 - POST
向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案)。資料被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。 - PUT
向指定資源位置上傳其最新內容。 - DELETE
請求伺服器刪除Request-URI所標識的資源。 - TRACE
回顯伺服器收到的請求,主要用於測試或診斷。 - CONNECT
HTTP/1.1協議中預留給能夠將連線改為管道方式的代理伺服器。
方法名稱是區分大小寫的。當某個請求所針對的資源不支援對應的請求方法的時候,伺服器應當返回狀態碼405(Method Not Allowed);當伺服器不認識或者不支援對應的請求方法的時候,應當返回狀態碼501(Not Implemented)。
HTTP伺服器至少應該實現GET和HEAD方法,其他方法都是可選的。此外,除了上述方法,特定的HTTP伺服器還能夠擴充套件自定義的方法。
安全方法
開發者應當意識到他們的軟體代表了使用者在因特網上進行互動,並且應當告知使用者,他們正在進行的操作可能對他們自身或者其他人有未曾預料的重要影響。
特別地,對於GET和HEAD方法而言,除了進行獲取資源資訊外,這些請求不應當再有任何其他意義。也就是說,這些方法應當被認為是“安全的”,即所謂安全的意味著該操作用於獲取資訊而非修改資訊。客戶端應當使用其他“非安全”方法,例如POST、PUT及DELETE來以特殊的方式(通常是按鈕而不是超連結)使得客戶能夠意識到可能要負的責任(例如一個按鈕帶來的資金交易)或者被告知正在請求的操作可能是不安全的(例如某個檔案將被上傳或刪除)。
但是,不能想當然地認為伺服器不會在處理某個GET請求時不會產生任何副作用。事實上,很多動態資源會把這作為其特性。這裡重要的區別在於使用者並沒有請求這一副作用,因此不應由使用者為這些副作用承擔責任。
冪等方法
假如在不考慮諸如錯誤或者過期等問題的情況下,若干次請求的副作用與單次請求相同或者根本沒有副作用,那麼這些請求方法就能夠被視作“冪等”的。GET,HEAD,PUT和DELETE方法都有這樣的冪等屬性,同樣由於根據協議,OPTIONS,TRACE都不應有副作用,因此也理所當然也是冪等的。
假如某個由若干個請求做成的請求序列產生的結果在重複執行這個請求序列或者其中任何一個或多個請求後仍沒有發生變化,則這個請求序列便是“冪等” 的。但是,可能出現若干個請求做成的請求序列是“非冪等”的,即使這個請求序列中所有執行的請求方法都是冪等的。例如,這個請求序列的結果依賴於某個會在下次執行這個序列的過程中被修改的變數。
1.4、HTTP響應的程式碼
伺服器程式響應的第一行叫狀態行。狀態行以HTTP版本號開始,後面跟著3位數字表示響應程式碼,最後是易讀的響應短語。根據第一位可以把響應分成5類:
圖6、HTTP響應程式碼
2、抓包分析
現在我們對HTTP基本上算是瞭解了,下面我用wireshark抓取開啟部落格園首頁時,我的電腦與部落格園伺服器的互動過程的HTTP資料包。做好準備工作,關閉一些可能干擾我們抓取開啟部落格園的相關程式。如下圖,我們在瀏覽器中輸入www.cnblogs.com並確定時,首先抓到如下包:
圖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請求的響應訊息是怎樣的:
響應訊息的狀態行是: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請求返回的。
圖9、POST資料包
我們可以看到,POST /ws/PublicUserService.asmx/GetLoginInfo HTTP/1.1。除了把GET換成了POST之外,其它資訊差不多。下面我們放大看下發送的首部欄位:
圖10、POST /ws/PublicUserService.asmx/GetLoginInfo HTTP/1.1的首部欄位
NOTE:本節涉及的一些首部欄位我就不在這裡解釋了。我想,到了這裡大家對HTTP的認識應該更深入了一步。
3、POST與GET的差異
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下就知道了。
4、以一個例項說明C#中如何使用POST、GET等操作
在介紹例項之前,我們要先介紹一下HttpWebRequest和HttpWebResponse,在C#中就是用這兩個類實現客戶端向伺服器端傳送HTTP訊息、客戶端接受伺服器端的HTTP響應。
4.1、HttpWebRequest
在設計實現例項之前我們首先要介紹一下HttpWebRequest這個類——提供WebRequest 類的HTTP 特定的實現,HttpWebRequest類對WebRequest中定義的屬性和方法提供支援,也對使使用者能夠直接與使用 HTTP 的伺服器互動的附加屬性和方法提供支援。
HTTP訊息的首部欄位(headers),在HttpWebRequest中表示為公開的屬性。下表列出了由屬性或方法設定或由系統設定的 HTTP 標頭。
如果本地計算機配置指定使用代理,或者如果請求指定代理,則使用代理髮送請求。如果未指定代理,則請求傳送到伺服器。
HttpWebRequest類主要包括如下方法,用於與HTTP伺服器互動:
- Abort: 取消對 Internet 資源的請求。
- AddRange: 向請求新增範圍標頭。
- BeginGetRequestStream:開始對用來寫入資料的 Stream 物件的非同步請求。
- BeginGetResponse:開始對Internet 資源的非同步請求。
- Create:初始化新的 WebRequest。(從WebRequest 繼承。)
- CreateDefault:為指定的 URI 方案初始化新的 WebRequest 例項。(從WebRequest 繼承。)
- CreateObjRef:建立一個物件,該物件包含生成用於與遠端物件進行通訊的代理所需的全部相關資訊。 (從MarshalByRefObject 繼承。)
- EndGetRequestStream:結束對用於寫入資料的 Stream 物件的非同步請求。
- EndGetResponse:結束對 Internet 資源的非同步請求。
- GetRequestStream:獲取用於寫入請求資料的 Stream 物件。
- GetResponse:返回來自 Internet 資源的響應。
- GetSystemWebProxy:返回當前模擬使用者的 Internet Explorer 設定中配置的代理。(從 WebRequest 繼承。)
- InitializeLifetimeService:獲取控制此例項的生存期策略的生存期服務物件。 (從 MarshalByRefObject 繼承。)
- RegisterPrefix:為指定的URI 註冊WebRequest 子代。(從WebRequest 繼承。)
4.2、HttpWebResponse
在設計實現例項之前我們還要介紹一下HttpWebRequest這個類——提供WebResponse 類的HTTP 特定的實現。此類包含對WebResponse類中的屬性和方法的 HTTP 特定用法的支援。HttpWebResponse類用於生成傳送HTTP請求和接收HTTP響應的HTTP獨立客戶端應用程式。
注意
不要混淆 HttpWebResponse 和 HttpResponse 類;後者用於 ASP.NET 應用程式,而且它的方法和屬性是通過 ASP.NET 的內部Response 物件公開的。
決不要直接建立HttpWebResponse類的例項。而應當使用通過呼叫 HttpWebRequest.GetResponse 所返回的例項。您必須呼叫Stream.Close 方法或 HttpWebResponse.Close 方法來關閉響應並將連線釋放出來供重用。不必同時呼叫 Stream.Close 和HttpWebResponse.Close,但這樣做不會導致錯誤。
從 Internet 資源返回的公共標頭資訊公開為該類的屬性。有關完整的列表,請參見下表。可以從 Headers 屬性以名稱/值對的形式讀取其他標頭。下表顯示可以通過HttpWebResponse類的屬性使用的公共 HTTP 標頭。
通過呼叫GetResponseStream方法,以Stream的形式返回來自 Internet 資源的響應的內容。
HttpWebRequest類主要包括如下方法與HTTP伺服器互動:(與HttpWebRequest類相比,方法較少)
- CreateObjRef:建立一個物件,該物件包含生成用於與遠端物件進行通訊的代理所需的全部相關資訊。(從MarshalByRefObject繼承。)
- GetLifetimeService:檢索控制此例項的生存期策略的當前生存期服務物件。(從MarshalByRefObject 繼承。)
- GetResponseHeader:獲取與響應一起返回的標頭的內容。
- GetResponseStream:獲取流,該流用於讀取來自伺服器的響應的體。
- InitializeLifetimeService:獲取控制此例項的生存期策略的生存期服務物件。(從 MarshalByRefObject 繼承。)
4.3、編寫WinForm程式開啟部落格園首頁(附原始碼)
通過前面兩小節的介紹,我們對HttpWebRequest類和HttpWebRequest類有所瞭解,現在我們就應用它們來編寫一個小程式來實踐。程式介面大概如下:
功能也比較簡單,就是通過點選“在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類的物件來實現的。
然而,通過點選“在WebBrowser中顯示”按鈕就在下方的 WebBrowser控制元件中顯示部落格園首頁的功能類似,只不過是在WebBrowser控制元件中顯示且我這裡把一些常用的HTTP相關的操作封裝到一個名稱空間Helper中,便於以後使用,本質跟上面的是一樣的。點選下載整個專案的原始碼。
我這個原始碼還是比較簡陋,只是簡單地實現了使用HttpWebRequest類和HttpWebRequest類與HTTP伺服器互動,更完善的功能期待你去完成。