http協議基礎知識總結

協議特點
1、基於請求和響應
客戶端向http服務器發起一次請求,服務器對請求做出響應,一來一回。
2、無連接
無連接是指在應用層無連接,限制每次連接只處理一次請求,也就是說客戶發起請求,服務器做出響應。連接即終止。這麼做的原因是http是基於互聯網的。服務器可能同時面對數十萬,百萬的請求。由於請求具有瞬時性,突發性。網頁瀏覽具有聯想性等等。造成相鄰兩次請求之間的關係可能不大。如果採用長時間連接的方式,大部分的網絡資源就會被空閒下來,造成浪費。所以講http協議設計成,請求時建立連接,響應時釋放連接,以儘快將資源釋放出來去服務其他客戶端。
但是http/1.1又推崇長連接的方式,這個我們在下面討論。
3、無狀態
無狀態是指http協議沒有記憶能力,當一次請求完畢後,它並不會將這次的數據保存下來。
缺點:下次請求的數據與上次相關聯的話,就得進行數據重傳,可能會造成每次傳輸的數據量都很大。
優點:在不需要上次的數據時,應答比較快。
4、簡單快速
協議簡單,一來一回就結束(一次請求,一次應答),使得http服務器的程序規模小,不需要去處理太複雜的邏輯,因而通信速度很快。
5、靈活
http協議允許傳輸任意類型的數據,類型有報文頭部的Content-Type指出。

總之,http協議的種種特點,都簡化http服務器的設計,使其可以接受大量高併發的請求。


http協議既然是基於請求和響應的,那麼就必須有請求和響應兩種報文。

請求報文
http協議的請求報文包含三個部分,請求行,請求頭部,空行,請求數據三部分構成。如下圖:

我們可以明顯看到一個特點,請求數據之上,每一行末尾都有一個回車換行,說明http協議報頭是嚴格以行爲單位的,切記這點。至於回車換行到底是兩個字符"\r\n"還是一個字符"\r"或者"\n",這個不用去深究,不同系統下格式也有所不同。
千萬要留意,請求頭部與請求數據之間有一行空行。這個空行作爲請求數據開始的標誌,也作爲請求頭部結束的標誌。

請求行
請求頭部由三部分構成,每個部分以空格作爲分隔符。
URL
我們先說第二部分URL。URL是一個統一資源標識符,標識着我們請求訪問的主機和請求資源在服務器上的存放路徑。它的格式如下:

http://host[":"port][abs_path][?name=value&name1=value1&...]

上面的是不是很眼熟,就是我們訪問網頁的網址,拋去“http://”剩下的部分就是報頭中的URL。
1、host :指我們要訪問的主機的IP或者域名。
2、port :指我們要訪問的主機的端口,如果不寫,默認爲80端口。
3、abs_path:指我們請求的資源的路徑。如果我們發送一個請求資源報文,至少指定abs_path爲“/”,意爲,請求web服務器根目錄下的資源。現在瀏覽器一般都幫我們完成了這個工作。
4、[?name=value&name1=value1&...] :有時我們需要向服務器傳遞一些參數,這時就以問好“?”作爲path和參數的分隔符,參數以name=value的形式給出,不同參數之間以取地址符“&”作爲分隔符。不過僅限於GET方法的參數會在url中顯示出。(會在下面分析)

下面看個例子:
我們在瀏覽器網頁窗口輸入“www.baidu.com”


當瀏覽器解析完畢後,自動爲我們加上了根目錄:


(https協議是http協議的一種加密版)

再看一個例子:
我們訪問CSDN的知識庫頁面:


lib.csdn.net就是域名,後面的一堆就是資源路徑。

第三個例子:
我們在平常瀏覽網頁的時候,可能經常看到這樣的網址。


以問好作爲其實的後面的一堆,就是參數。

大家可能注意到,我在訪問這兩個網站的時候都沒有加端口號,還是成功訪問了,這就是默認了80端口。

請求方法

現在互聯網上的資源多種多樣,http的請求方法自然也有很多種。每一種都有不同的目的。
這裏大家先分清楚兩個概念:
  1. 靜態頁面請求,靜態頁面請求就是向服務器請求一張html頁面,我只看看,別的不做。
  2. cgi請求:cgi請求是請求服務器的一個外部程序。比如久久時間網的計算時間功能,我們向服務器提交一些參數,服務器通過調用外部程序進行運算再將結果返還給我們。

GET:請求獲取URL所標識的資源(是不是很好理解了),GET請求就有以上描述的兩種請求方式之分。
  1. 不帶參數的GET,爲靜態頁面請求,就是我們平常的普通瀏覽頁面。
  2. 帶參數的GET,cgi請求。(參數會在url中顯示出)

POST:與帶參數的get方法用法相似,只要是post方法,就一定是cgi請求。post的參數放在報文第三部分請求數據中,參數的長度在報文第二部分的Content-Length給出。post方法常用於提交表單。
HEAD:請求獲取由URL標識的資源的響應報文。
PUT:請求服務器存儲一個資源,並用URL作爲標識。
DELETE:請求服務器刪除URL所標識的資源。
TRACE:請求服務器回送收到的請求消息,主要用於測試或診斷。
CONNECT:保留將來使用
OPTIONS:請求查詢服務器的性能,或者查詢與資源相關的選項和需求。


請求協議

請求協議一般是HTTP/1.0,不過近年來開始流行HTTP/1.1。


請求頭部
請求頭部允許客戶端向服務器傳遞請求的附加信息以及客戶端自身的信息。
採用name:value的形式,以行爲單位。
常用的請求頭部如下:
Accept : 指定客戶端接受那些類型的信息。如:Accept:text/html 表示客戶端可接受html類型的文本數據。
Accept-Charset:指定客戶端接受的字符集,如果沒有明確指定,表示任何字符集都可接受。
Accept-Encoding:指定可接受的內容編碼。
Accept-Language:指定一種自然語言
Authorization:用於驗證客戶端有權查看某個資源,當瀏覽器訪問一個頁面時,如果收到服務器的響應代碼爲401(未授權),可以發送一個包含Authorization請求報頭域的請求,要求服務器對其進行驗證。

下面看一個完整的請求報文。

POST /cgi/cgifun HTTP/1.1
Host: 192.168.3.21:8080
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20131029 Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://192.168.3.21:8080/
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
空行
firstname=Mickey&firstname=Mickey&lastname=Mouse&firstname=Mickey(請求數據/POST的參數)




響應報文

同樣響應報文格式和請求報文保持一致,只是內容有些改變。響應報文由響應行,響應頭部,空行,響應數據四部分組成。
把請求報文的圖照搬下來,名字變一下就是了。
響應報文與請求報文的最大不同點在於第一行,響應行。
響應行
響應行也是由三部分構成,協議版本,響應狀態碼,響應狀態碼文本描述。如下面這行數據:

HTTP/1.0 200 ok

響應狀態碼爲200,表示成功響應,文本描述爲OK。響應狀態碼有很多種。
1xx:表示請求已接受,繼續處理
2xx:表示請求已被成功接受,理解,接受
3xx:重定向,要完成請求必須更進一步的操作。
4xx:客戶端錯誤,請求有語法錯誤或請求無法實現。
5xx:服務端錯誤,服務器未能實現合法的請求。

常見的狀態碼有:(後面的英文是對應的文本描述)
200 OK      //客戶端請求成功
400 Bad Request  //客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized //請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用
403 Forbidden  //服務器收到請求,但是拒絕提供服務
404 Not Found  //請求資源不存在,eg:輸入了錯誤的URL
500 Internal Server Error //服務器發生不可預期的錯誤
503 Server Unavailable  //服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

響應頭部
響應頭部允許服務器傳遞不能放在狀態行中的響應信息,以及關於服務器的信息和對於URL所標識的資源進行下一步訪問的信息。
Location:響應報頭域用於重定向接受者到一個新的位置。Location響應報頭域常用在更換域名的時
Server:響應報頭域包含了服務器用來處理請求的軟件信息。與User-Agent請求報頭域是相對應的。
WWW-Authenticate:響應報頭域必須被包含在401(未授權的)響應消息中,客戶端收到401響應消息時候,併發送Authorization報頭域請求服務器對其進行驗證時,服務端響應報頭就包含該報頭域。
eg:WWW-Authenticate:Basic realm="Basic Auth Test!"  //可以看出服務器對請求資源採用的是基本驗證機制。

關於頭部部分,除了上述所說的響應頭部和請求頭部之外還有以下幾種常見屬性。
普通頭部
在普通頭部中,有少數報頭域用於所有的請求和響應消息,但不用於被傳輸的實體,只用於傳輸的消息。
Cache-Control:用於指定緩衝指令。緩存指令是單向的(響應中出現未必請求中也出現),獨立的(一個消息中的緩存指令不會影響另一條消息)
請求時的緩存指令包括:no-cache(用於指示請求或響應消息不能緩存)、no-store、max-age、max-stale、min-fresh、only-if-cached;
響應時的緩存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage.


Date:普通報頭域表示消息產生的日期和時間
Connection:普通報頭域允許發送指定連接的選項。例如指定連接是連續,或者指定“close”選項,通知服務器,在響應完成後,關閉連接

實體頭部
請求和響應消息都可以傳送一個實體。一個實體由實體報頭域和實體正文組成,但並不是說實體報頭域和實體正文要在一起發送,可以只發送實體報頭域。實體報頭定義了關於實體正文(eg:有無實體正文)和請求所標識的資源的元信息。
常用的實體報頭
Content-Encoding
Content-Encoding實體報頭域被用作媒體類型的修飾符,它的值指示了已經被應用到實體正文的附加內容的編碼,因而要獲得Content-Type報頭域中所引用的媒體類型,必須採用相應的解碼機制。Content-Encoding這樣用於記錄文檔的壓縮方法,eg:Content-Encoding:gzip
Content-Language
Content-Language實體報頭域描述了資源所用的自然語言。沒有設置該域則認爲實體內容將提供給所有的語言閱讀
者。eg:Content-Language:da
Content-Length
Content-Length實體報頭域用於指明實體正文的長度,以字節方式存儲的十進制數字來表示。
Content-Type
Content-Type實體報頭域用語指明發送給接收者的實體正文的媒體類型。eg:
Content-Type:text/html;charset=ISO-8859-1
Content-Type:text/html;charset=GB2312
Last-Modified
Last-Modified實體報頭域用於指示資源的最後修改日期和時間。
Expires
Expires實體報頭域給出響應過期的日期和時間。爲了讓代理服務器或瀏覽器在一段時間以後更新緩存中(再次訪問曾訪問過的頁面時,直接從緩存中加載,縮短響應時間和降低服務器負載)的頁面,我們可以使用Expires實體報頭域指定頁面過期的時間。eg:Expires:Thu,15 Sep 2006 16:23:12 GMT
HTTP1.1的客戶端和緩存必須將其他非法的日期格式(包括0)看作已經過期。eg:爲了讓瀏覽器不要緩存頁面,我們也可以利用Expires實體報頭域,設置爲0,jsp中程序如下:response.setDateHeader("Expires","0");

以上關於報文頭部的知識來自於http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html



長連接與短連接

http協議在應用層是無連接的,但在傳輸層,它使用TCP協議,還是需要建立一定的連接。http的TCP連接有兩種,長連接與短連接。

短連接
短連接指:一次連接只支持一次數據的發送或接受,當數據交互完畢後,立即關閉連接
客戶端請求連接---服務端響應,建立連接(三次握手) --- 傳輸數據 --- 服務端關閉連接 (四次揮手)

短連接的好處:短連接邏輯簡單,一來一回即關閉連接,這樣可以加快服務器的處理速度,提高服務器的工作效率。一定程度上可以簡化http服務器代碼邏輯,使其變的更簡單。


長連接
長連接:一次連接支持多次數據的交互,當沒有數據的交互時,有心跳機制來維護持續的連接。
客戶端請求連接---服務端響應,建立連接(三次握手) --- 傳輸數據 --- 心跳 --- 傳輸數據 --- 心跳 --- ... --- 關閉連接

長連接的好處:
1、可以減少TCP建立連接三次握手與釋放連接四次揮手所造成開銷,減少網絡流量。
2、在連續的請求同一服務器時,可以降低網絡延遲。在使用https時效果明顯,可以減少SSL/TLS所造成的大量開銷。(加密解密算法)
3、讓TCP有足夠的時間判斷網絡擁塞狀況,方便下步操作。

長連接也有不好的地方:
1、容易被攻擊,當惡意用戶想服務器發起了多個長連接請求,但是不進行數據交互,那麼在那一段時間內,服務器的大部分資源都被這些長連接佔據,此時其他用戶就無法訪問該服務器。
2、當維持大量長連接是,服務器的壓力會大大增大。


TIME-OUT與心跳機制
客戶端發起的長連接不可能長時間佔用服務器資源,一般在報文的頭部中有個Keep-Alive選項會指明timeout時間或者指明max次數,一旦超過這個事件或一旦超過請求的max次數,這個連接就會自動斷開。
當沒有超過範圍,並且在連接空閒情況下,客戶端與服務器之間會以心跳包的方式來維護連接,每隔一段時間客戶端或者服務器就會發出一個心跳檢測包,如果對端給出了迴應報文,則繼續維護連接。否則斷開連接。



在web開發中,http長連接與瀏覽器併發連接的數量限制也有一定的關係。
爲什麼要瀏覽器要有併發連接數的限制?
1、TCP協議的限制,PC端只有65536個端口可以向外部發出連接,而操作系統對半開連接數也有限制以保護操作系統的TCP/IP協議棧資源不被迅速耗盡。因此瀏覽器不好發出太多的TCP連接。而是採取連接複用(長連接)或者等一次連接完畢再重新建立連接的方式。(半開連接指的是 TCP 連接的一種狀態,當客戶端向服務器端發出一個 TCP 連接請求,在客戶端還沒收到服務器端的迴應併發回一個確認的數據包時,這個 TCP 連接就是一個半開連接。若服務器到超時以後仍無響應,那麼這個 TCP 連接就等於白費了,所以操作系統會本能的保護自己,限制 TCP 半開連接的總個數,以免有限的內核態內存空間被維護 TCP 連接所需的內存所浪費。)
2、 如果採用阻塞的套接字模型來建立連接,同時發出多個連接會導致瀏覽器不得不多開幾個線程,而線程有時候算不得是輕量級資源,畢竟做一次上下文切換開銷不小。
3、保護服務器,減小服務器的壓力。還因爲當一個強勢的連接請求與一個弱勢的連接請求同時訪問服務器時,搶手者會一直佔用服務器,導致弱勢者無法訪問公共資源。
爲了迎合瀏覽器併發連接數的限制,長連接是一個很好的選擇。

關於上面提到的瀏覽器的併發連接也可理解爲一種http連接方式,稱爲並行連接。
並行連接
由於現代網頁通常包含了複數個(>=10)資源,而按照默認設定,一個連接中的每一個請求必須等待收到響應後才能發送下一個請求,所以如果複數的資源請求全部在一個連接one by one發送給服務器顯然會很慢,而爲了彌補這一缺陷,瀏覽器通常會默認開啓多個TCP連接,然後再根據每個連接的狀態在其中依次發送數據請求,而且客戶端有權任意關閉超發的連接。各個瀏覽器允許的並行連接數大致是這樣的(From SO):
Firefox 2:   2
Firefox 3+:  6
Opera 9.26:  4
Opera 12:   6
Safari 3:   4
Safari 5:   6
    IE 7:       2
    IE 8:       6
    IE 10:      8
    Chrome:      6

由於TCP協議本身有慢啓動的特徵,會隨着時間調諧連接的最大速度,因此在現代瀏覽器中持久連接和並行連接通常是搭配在一起使用的—— 一方面由於持久連接的存在,每個TCP連接已經處於調諧後的狀態,另一方面持久連接可以避免重新三次握手的開銷。

管道持久化連接
按照HTTP1.1的描述,還有種可以提升性能的方案是管道化,可以在一個連接中發送多個請求不必等待前一個請求返回。但這項技術比較容易踩坑,所以主流面向用戶的瀏覽器,這項技術是被默認關閉。管道化的具體情形如下圖:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章