HTTP是一種無狀態、由文本構成的請求-響應(request-response)協議,這種協議使用的是客戶端-服務器(client-server)計算模型。
請求-響應是兩臺計算機進行通信的基本方式,其中一臺計算機會向另一臺計算機發送請求,而接收到請求的計算機則會對請求進行響應。在客戶端-服務端計算模型中,發送請求的一方(客戶端)負責向返回響應的一方(服務器)發起會話,而服務端則負責爲客戶提供服務。在HTTP協議中,客戶端也被稱爲用戶代理(user-agent),而服務器則通常會被稱爲Web服務器。
HTTP是以純文本方式而不是二進制方式發送和接收協議數據的。
CGI(Common Gateway Interface)通用網關接口。簡單理解,可以認爲CGI是Web服務器和一個獨立的進程之間的協議,它會把HTTP請求Request的Header頭設置成進程的環境變量,HTTP請求的Body正文設置成進程的標準輸入,進程的標準輸出設置爲HTTP響應Response,包含Header頭和Body正文。
HTTP是一種請求-響應協議,協議涉及的所有事情都以一個請求開始。HTTP請求跟其他所有HTTP保溫(message)一樣,都由一系列文本行組成,這些文本行會按照以下順序進行排列:
(1)請求行(request-line);
(2)零個或任意多個請求首部(header);
(3)一個空行;
(4)可選的報文主體(body)。
如下圖:
請求行的第一個單詞爲請求方法,之後跟着的是統一資源標識符(Uniform Resource Identifier, URI)以及所使用的HTTP版本。位於請求行之後的兩個文本行爲請求的首部。
請求方法是請求行中的第一個單詞,他指明瞭客戶端想要對資源執行的操作。HTTP0.9只有GET一個方法,HTTP1.0添加了POST方法和HEAD方法,而HTTP1.1則添加了PUT、DELETE、OPTIONS、TRACE和CONNECT這五個方法,並允許開發者自行添加更多方法。
各個HTTP方法的作用說明如下:
如果一個HTTP方法只要求服務器提供信息而不會對服務器的狀態做任何修改,那麼這個方法就是安全的(safe)。GET、HEAD、OPTIONS和TRACE都不會對服務器的狀態進行修改,所以他們都是安全的方法。
如果一個HTTP方法在使用相同的數據進行第二次調用的時候,不會對服務器的狀態造成任何改變,那麼設個方法就是冪等的。根據安全的方法的定義,因爲多有安全的方法都不會修改服務器狀態,所以他們天生就是冪等的。
PUT和DELETE雖然不安全,但卻是冪等的,因爲他們在進行第二次調用的時候都不會改變服務器的狀態:因爲服務器在執行第一個PUT請求之後URI指定的資源已經更新或者創建出來了,所以針對同一個資源的第二次PUT請求只會執行服務器已經執行過的動作;與此類似,雖然服務器對於同一個資源的第二次PUT請求只會執行服務器已經執行過的動作;與此類似,雖然服務器對於同一個資源的第二次DELETE請求肯能會返回一個錯誤,但這個請求並不會改變服務器的狀態。
GET方法是最基本的HTTP方法,它負責從服務器上獲取內容,所有瀏覽器都支持這個方法。POST方法從HTML2.0開始可以通過添加HTML表單來實現:HTML的form標籤有一個名爲method的屬性,用戶通過將這個屬性的值設置爲get或者post來指定要使用那個方法。HTML不支持除GET和POST之外的其他HTTP方法。
但是,現在流行的瀏覽器通常都不會只支持HTML一種數據格式——用戶可以使用XMLHttpRequest(XHR)來或得對PUT方法和DELETE方法的支持。XHR是一系列瀏覽器API,這些API通常由JavaScript包裹(實際上XHR就是一個名爲XMLHttpRequest的瀏覽器對象)。XML允許程序員向服務器發送HTTP請求,並且跟「XMLHttpRequest」這個名字所暗示的不一樣,這項技術並不僅僅侷限於XML格式——包括JSON以及純文本在內的任何格式的請求和響應都可以通過XHR發送。
HTTP請求方法定義了發送請求的客戶端想要執行的動作,而HTTP請求的首部則記錄了與請求本身及客戶端有關的信息。請求的首部由熱議多個冒號隔開的純文本鍵值對組成,最後以回車(CR)和換行(LF)結尾。
常見的請求首部:
首部字段 | 作用描述 |
---|---|
Accept | 客戶端在HTTP響應中能夠接收的內容類型。比如說,客戶端可以通過Accept:text/html這個首部,告知服務器自己希望在響應的主體中收到HTML類型的內容 |
Accept-Charset | 客戶端要求服務器使用的字符集編碼。比如客戶端可以通過Accept-Charset:uft-8這個首部,告知服務器自己希望響應的主體使用UTF-8字符集。 |
Authorization | 這個首部用於向服務器發送基本的身份驗證證書 |
Cookie | 客戶端應該在這個首部中把服務器之前設置的所有cookie回傳給服務器。比如說,如果服務器之前在瀏覽器上設置了3個cookie,那麼Cookie首部字段將在一個字符串裏面包含這三個cookie,並使用分號對這些cookie進行分割。以下是一個Cookie首部示例:Cookie: my_first_cookie=hello; my_second_cookie=world |
Content-Length | 請求主體的字節長度 |
Content-Type | 當請求包含主體的時候,這個首部用於記錄主體內容的類型。在發送POST或PUT請求時,內容的類型默認爲x-www-form-urlen-coded,但是在上傳文件時,內容的類型應該設置爲multipart/form-data(上傳文件這一操作可以通過將input標籤的類型設置爲file來實現) |
Host | 服務器的名字以及端口號。如果這個首部沒有記錄服務器的端口號,就表示服務器使用的是80端口。 |
Referrer | 發送請求的頁面所在的地址 |
User-Agent | 對發起的客戶端進行描述 |
HTTP響應報文是對HTTP請求報文的回覆。跟HTTP請求一樣,HTTP響應也由一系列文本行組成,其中包括:
HTTP響應狀態碼總共有5種類型,他麼分別以不同的數字作爲前綴,如下表:
狀態碼類型 | 作用描述 |
---|---|
1XX | 情報狀態碼。服務器通過這些狀態碼來告知客戶端,自己已經接收到了客戶端發送的請求,並且已經對請求進行了處理。 |
2XX | 成功狀態碼。這些狀態碼說明服務器已經接收到了客戶端發送的請求,並且已經成功的對請求進行了處理。這類狀態碼的標準響應爲「200 OK」 |
3XX | 重定向狀態碼。這些狀態碼錶示服務器已經接收到了客戶端發送的請求,並且已經處理了請求,但是爲了完成指定的動作,客戶端還需要在做一切其他的 工作。這類狀態碼大多用於實現URL重定向。 |
4XX | 客戶端錯誤狀態碼。這類狀態碼說明客戶端發送的請求出現了某些問題。在這一類型的狀態碼種,最常見的就是「404 Not Found」,這個狀態碼錶示服務器無法從請求的URL中找到客戶端想要的資源。 |
5XX | 服務器錯誤狀態碼。當服務器因爲某些原因而無法正確的處理請求時,服務器就會使用這類狀態碼來通知客戶端。這一類狀態碼中,最常見的就是」500 Internal Server Error「狀態碼。 |
響應首部跟請求首部一樣,都是由冒號分隔的純文本鍵值對組成,並且同樣以(CR)和換行符(LF)結尾。下表爲常見的響應首部:
首部字段 | 作用描述 |
---|---|
Allow | 告知客戶端,服務器支持那些請求方法 |
Content-Length | 響應主體的字節長度 |
Content-Type | 如果響應包含可選的主體,那麼這個首部記錄的就是主體內容的類型 |
Date | 以格林尼治標準時間(GMT)格式記錄的當前事件 |
Location | 這個首部僅在重定向時使用,他會告知客戶端接下來應該向那個URL發送請求 |
Server | 返回響應的服務器的域名 |
Set-Cookie | 在客戶端裏面設置一個Cookie。這個相應裏面可以包含多個Set-Cookie的首部。 |
W-W-W-Authenticate | 服務器通過這個首部告知客戶端,在Authorization請求首部中應該提供哪些類型的身份驗證信息。服務器常常會把這個首部與「401 Unauthorized」狀態行一同發送。除此之外,這個首部還會向服務器許可的認證授權模式(schema)提供驗證信息 |
URI(Uniform Resource Location, 統一資源定位符)是一個涵蓋性術語,它包含了URN(Uniform Resource Name, 統一資源名稱)和URL,並且這兩者也擁有相似的語法和格式。
URI的一般格式爲:<方案名稱>:<分層部分>[ ? <查詢參數> ][ # <片段> ]
URI中的方案名稱(scheme name)記錄了URI正在使用的方案,它定義了URI其餘部分的結構。因爲URI是一種非常常用的資源標識方式,所以它擁有大量的方案可供使用。
URI的分層部分(hierarchical part)包含了資源的識別信息,這些信息會以分層的方式進行組織。如果分層部分以雙斜線(//)開頭,那麼說明它包含了可選的用戶信息,這些信息將以@符號結尾,後跟分層路徑。不帶用戶信息的分層部分就是一份單純的路徑,每個路徑都由一連串的分段(segment)組成,各個分段之間使用但斜槓(/)分隔。
在URI的各個部分當中,只有「方案名稱」和「分層部分」是必須的。以問好(?)爲前綴的查詢參數(query)是可選的,這些參數用於包含無法使用分層方式表示的其他信息。多個查詢參數會被組織成一連串的鍵值對,各個鍵值對之間只用&符號分割。
URI的零一個可選部分爲片段(fragment),片段使用井號(#)作爲前綴,它可以對URI定義的資源中的次級資源(secondary resource)進行標識。當URI包含查詢參數時,URI的片段將被放到查詢參數之後。因爲URI的片段是由客戶端負責處理的,所以Web瀏覽器在將URI發送給服務器之前,一般都會先把URI中的片段移除掉。如果程序員想要取得URI片段,那麼可以通過JavaScript或者某個HTTP客戶端庫,將URI片段包含在一個GET請求裏面。