一、前言
前段時間為了研究計算機網絡,看了看《計算機網絡自頂向下方法》這本書。不得不說這真是一本好書,內容詳細,而且講解的淺顯易懂,采用了大量類比的方式進行講解,而不是單純的敘述理論,同時在每一章的后面都有大量的練習題以及很有意思的編程題,所以開頭先來推薦一波。這本書我暫時只看到了第二章,剛看完HTTP
的內容,所以寫一篇HTTP
相關的博客,就當是記筆記了。
二、詳解
2.1 HTTP概述
HTTP
是一個應用層的協議,全稱是超文本傳輸協議,它是web
的核心。HTTP
由兩個程序實現——客戶端程序和服務端程序,而HTTP
的作用簡單來說就是客戶端向服務器發請求,而服務器根據請求做出響應。HTTP
定義了Web
客戶端向服務器請求資源的方式,以及Web
服務器向客戶端回送資源的方式,也就是HTTP
的請求+響應模型。客戶端向服務器發送請求報文請求資源,服務器接收到請求,向客戶端回送包含這些資源的響應報文。
HTTP
基於TCP
協議,由TCP
協議支持數據的傳輸,這說明HTTP協議是一個面向連接的可靠協議。當客戶端向服務器請求資源時,首先將與服務器建立一個TCP
連接,當TCP
連接建立成功時,客戶端和服務器之間就可以通過套接字接口訪問TCP
,客戶端通過TCP
連接傳輸請求報文,而服務器也通過這個TCP
連接回送響應報文及資源。由於TCP
的可靠傳輸,保證了HTTP
的報文一定能夠完整的送到服務器上,而服務器的響應也能完整的回送到客戶。
HTTP
請求的資源一般是一個Web
頁面,而一個Web
頁面是由一個或多個對象組成的,這個對象可能是一個html
文件,一張圖片,甚至是一段視頻或者小程序。對於HTTP
來說,組成一個Web
頁面的這些對象並不屬於同一個資源,每一個對象都是一個單獨的資源,需要逐一請求。假設我們向服務器請求一個Web
頁面,這個頁面由一個html
文件以及5
張圖片組成(html
通過路徑引用圖片),則這個頁面共有6
個對象,當服務器接收到客戶端對頁面的請求后,將html
文件通過響應報文返回,而客戶端接收到響應的html
文件后,發現它還引用了5
張圖片,這時客戶端將再次發送5
個HTTP
請求,來分別請求這5
張圖片。
服務器向客戶端發送被請求的文件,但是不記錄任何客戶的信息,所以當你連續向服務器請求同一份資源兩次時,服務器也會給你響應兩次,不會因為你已經請求過就不給你響應了。正是因為HTTP
不記錄客戶的信息,所以它也是一個無狀態協議。
2.2 非持續連接和持續連接的HTTP
大多數情況下,我們對Web
服務器發出請求時,都不止發出一個請求,比如上面說到的包含5張圖片的頁面。那這個時候就需要考慮一個問題,對於這多次目的地相同的請求/響應,HTTP
是對每一個請求/響應使用同一個TCP
連接,還是每次請求單獨創建一個TCP
連接呢?這里就分兩種情況,多次請求/響應使用同一個TCP
連接的被稱為持續連接,而每個請求/響應單獨使用一個TCP
連接,則被稱為非持續連接。而HTTP
默認使用的是持續連接,但是也可以通過配置,改用非持續連接。下面就來簡單說一說兩者的區別。
(1)非持續連接
非持續連接表示對於每一個請求/響應,都將單獨建立一個TCP
連接來進行。假設我們還是以之前說過的例子來講解:我們向服務器請求一個包含5
張圖片的頁面,而頁面的路徑假設就是HTTP://www.tewuyiang.cn/index.html(這是我的個人服務器,目前部署了一個制作簡單的小游戲),當我們請求這個路徑時,將發生以下情況:
HTTP
客戶進程通過80端口向服務器www.tewuyiang.cn
發起一個TCP
連接,80
端口時HTTP
的默認端口;HTTP
客戶進程通過套接字向服務器發送一個請求報文,請求資源的路徑為/index.html
;HTTP
服務器進程通過套接字接收到該請求,從它的存儲器(如:RAM)中搜索HTTP://www.tewuyiang.cn/index.html這個資源,生成一份響應報文,並將html
頁面封裝進響應報文中,並通過套接字將此報文回送給客戶端;HTTP
服務器通知TCP
斷開連接(但是直到TCP
確認客戶端已經接收到完整的報文后,才會將連接斷開);HTTP
客戶進程完整的接收到響應報文好,TCP
連接斷開。客戶端解析響應報文后,發現封裝的對象是一個html
文件,且html
文件包含5
張圖片的引用;- 重復上面步驟
1-4
,請求頁面包含的5
張圖片;
非持續連接的缺點很明顯,那就是對於每一個請求/響應都需要建立TCP
連接,這樣將導致服務器需要維護的連接大大增加,比如一個頁面包含10
張圖片,那總共就得2
建立11
給連接,這樣將給服務器造成巨大的壓力。而好處就是,多個連接可以同時建立(一個瀏覽器一般可以同時建立5-10
個連接),表示有多個通道,通道之間傳輸數據是並行的,多個請求/響應可以同時進行,這樣就不會造成排隊的情況,效率較高。
(2)持續連接
持續連接表示某個客戶端與一個服務器建立連接后,在一段時間內,向服務器發送的請求以及服務器發送的響應,都可以通過這一條連接來進行。這個應該很好理解。而持續連接也分為兩種:
- 不帶流水線的持續連接:這表示一次性只能進行一個請求/響應,而下一個必須得等上一次完成后才進行;
- 帶流水線的持續連接:這表示對對象的請求可以一個個發出,而不需要等未完成的請求結束(但不是完全並行);
對於長時間未使用的連接,HTTP
會將它關閉,而這個超時時間也可以進行配置。
持續連接的好處也很明顯,那就是節省資源,多個請求共用一個連接;但是缺點就是效率可能相對要低一些。HTTP的默認模式就是帶流水線的持續連接。
2.3 HTTP報文格式
接下來,我們就來談一談HTTP協議的報文格式吧。HTTP
的報文分為請求報文和響應報文。
(1)請求報文
下面是一段我從瀏覽器截取下來的HTTP
的請求報文,請求的資源是一張圖片:
HTTP
請求報文的第一行為請求行,剩下的都叫首部行,下面我來一行一行解釋上面的內容:
首先是第一行,也就是請求行,它包含三部分內容:請求方法,資源路徑,HTTP協議版本,它們三者由空格隔開。第一部分的請求方法表示客戶端向瀏覽器發送的請求的類別,我們常用的請求方式是GET
和POST
請求:
- GET:向服務器請求資源,服務器將請求的資源返回;
- POST:向服務器提交數據並請求處理(比如說提交表單),數據被包含在請求體中。
POST
請求可能會導致新的資源的建立和/或已有資源的修改;
上面兩個請求方式都是HTTP1.0
中定義的,而HTTP1.0
除了上面兩個請求方法,還有一個HEAD
請求:
- HEAD:類似於 GET 請求,只不過返回的響應中沒有具體的內容,用於獲取報頭;
在HTTP1.1
中,又新增了六種請求,分別是OPTIONS
、PUT
、PATCH
、DELETE
、TRACE
和 CONNECT
方法,它們的定義我就不一個個列出來了,大家可以點擊后面的連接查閱——HTTP請求方法。
緊隨請求方法之后的是資源在HTTP
服務器上的路徑,報文中的路徑是/img/prop3.png
,表示我們請求的是HTTP
服務器路徑下,img
文件夾下的prop3.png
這張圖片。這之后的HTTP1.1
表示的就是這次請求使用的HTTP
的版本了。
請求行下面的都是首部行,而首部行都是name: value
格式的,name
表示這個首部的名字,而value
就是首部的具體值了。第一個首部行的名字叫Host
,表示的是HTTP
服務器所在的地址,而這里的地址是www.tewuyiang.cn。第二個首部行的名字是Connection
,這個表示的就是我們上面提到的HTTP
的連接類型了,而它的值是keep-alive
,就是告訴服務器,使用的是持續連接,若值為close,表示的就是非持續連接。第三個首部行User-Agent
的作用就是指明用戶代理,也就是告訴服務器,發送這次HTTP請求的瀏覽器的類型。第四個首部行Accept的作用告訴服務器自己希望接收的資源的類型,若服務器響應的資源與此不一致,將會報錯,而從上面的報文中可以看出,這個請求希望受到一張圖片。Referer
的作用是用來防止惡意請求,提高訪問資源的安全性。Accept-Encoding
的作用是告知服務器,當前瀏覽器支持的編碼類型。Accept-Language
的作用是告知HTTP
服務器客戶端想要獲取資源的語言版本,若服務器中不包含此語言版本,則將回送默認版本。
下面這張圖是HTTP
請求報文的標准格式:
(2)響應報文
同樣,我們先來看一段響應報文:
響應報文的第一段由兩部分組成,分別是HTTP版本以及狀態碼,上面的報文中,HTTP
的版本為1.1
,與請求的版本相同,之后緊跟的狀態碼為200
,這是最常見的狀態碼,表示請求成功。若還想知道其他狀態碼,可以點擊菜鳥教程查閱,這里列出常見的四種:
- 200 - 請求成功;
- 301 - 資源(網頁等)被永久轉移到其它URL;
- 404 - 請求的資源(網頁等)不存在;
- 500 - 內部服務器錯誤;
第一行之后的這些行,被稱為首部行,與請求報文中的首部行類似,也是name: value
。第一個首部行的名稱叫做Accept-Ranges
,它的作用是告知客戶端,此資源是否支持范圍請求,而范圍請求可以支持斷點續傳和多線程分片下載,bytes
表示支持,而none
表示不支持。Last-Modified
的作用后面說緩存時單獨拿出來說。Content-type
的作用就是標識資源的類型,這里image/png
表示資源是一張圖片。Content-Length
表示資源的字節數,圖片中的值是8729
,表示這張圖片共有8729
個字節。最后一個Date
的作用就是表示服務器發送該響應報文的日期時間。
下面這一張是HTTP
響應報文的標准格式,可以看到,在最后面還有一個叫實體體的部分,這里就是用來放服務器回送的資源的,例如請求的圖片。
2.4 Web緩存器
Web緩存器也叫代理服務器,它在某些情況下可以代替HTTP
服務器滿足客戶的需求。Web
緩存器有自己的存儲空間,並保存有最近被請求資源的副本。它的作用故名思意,就是提供緩存機制的。若部署了Web緩存器,則可以配置瀏覽器,使得瀏覽器的HTTP
請求首先發送至Web
緩存器,下面我們通過一個例子來講解Web
緩存器的機制。
假設我現在要請求www.tewuyiang.cn這個服務器上的prop3.png
這張圖片,結果將發生以下情況:
HTTP
客戶端創建一個到Web
緩存器的TCP
連接,並向Web
緩存器發送一個請求報文;Web
緩存器接收到請求報文,查看自己的本地是否包含被請求資源的副本,若包含,則由Web
緩存器創建響應報文,並將此副本通過響應報文返回給HTTP
客戶端;- 若
Web
緩存器中不包含此資源的副本,則Web
緩存器將向HTTP
服務器(這里指的就是www.tewuyiang.cn)發起一個TCP
連接,並向服務器請求客戶端需要的資源; - 服務器創建響應報文,將請求的資源響應給緩存器,緩存器接收到響應報文,解析響應報文攜帶的資源,並復制一份副本存儲在本地,然后重新創建一份響應報文,並將副本封裝進其中,發送給最初請求資源的客戶端;
通過上面的步驟我們可以看到,Web
緩存器在這個過程中,既充當服務器的角色,又充當客戶端的角色。而部署了Web
緩存器后,將大大減少服務器響應資源的時間。
2.5 條件GET方法
介紹完上面的Web
緩存器后,很多人可能會有一個疑問:怎么能夠保證Web緩存器上的資源是最新的呢,若服務器上的資源被更新,而我們請求獲得的卻是緩存器上沒有被改變的舊資源怎么辦?HTTP
自然是有辦法解決這個問題,這時候就要用到我們在講解響應報文時跳過的首部行Last-Modified了,而這種機制叫做條件GET。
Last-Modified
首部行記錄的是當前被請求的資源,在服務器上最后被修改的時間。當我們請求一個Web
緩存器上沒有的資源時,Web
緩存器向HTTP
服務器轉發該請求,而服務器響應緩存器,同時在響應報文中包含Last-Modified
首部行。Web
緩存器在存儲資源的副本時,同時也將Last-Modified
的值存了下來。當下一次有客戶端請求此資源時,Web
緩存器會發送一個條件GET
請求到服務器,請求中包含這個時間值,且此時的命名為Last-Modified-Since
。服務器接收到這個時間值后,將它與服務器本地記錄的這個資源的最后修改時間進行比較,若兩者相等,表示上次請求到這次請求之間,這個資源並未更新,服務器將告知Web
緩存可以直接使用它存儲的副本;若兩者不相同,則服務器會將最新的資源,以及新的Last-Modified
發送至Web
緩存器,Web
緩存器更新本地的副本,並響應給客戶端。
三、總結
上面的內容對HTTP
協議以及它的一些機制進行了一個大致的介紹,相信看完之后,能夠讓你對HTTP
有一個大致的了解。當然HTTP
的內容肯定不止這些,只是限於篇幅,以及我的知識儲備,這篇博客就先寫上這些吧。日后有時間,再寫一寫HTTP
的其他部分,例如cookie
和session
。
四、參考
《計算機網絡——自頂向下方法(原書第七版本)》