哈嘍,小夥伴們,大家好,我是小智。
前面的準備工作都做好了,現在我們就要真正開始學習網絡協議知識了。
在上一章節中,我們使用 Wireshark,簡單分析過訪問世界上第一個網站http://info.cern.ch(後面簡稱 cern 網站)的 HTTP 報文,不過這個分析太過於簡單。由於 HTTP 使用得非常廣泛,在網際網路公司面試中,HTTP 也被經常問到,所以我們有必要比較系統的來學習一下它。
這個章節包含的內容如下:
正文HTTP是什麼HTTP,全稱HyperText Transfer Protocol,中文名稱為超文本傳輸協議。
單從名字上來看,我們基本可以確定它是一個傳輸超文本的網絡協議。那這裡有三個問題:
傳輸:是從哪裡傳輸到哪裡?
HTTP 是在瀏覽器(客戶端)和網站(伺服器)之間傳輸數據,它是一種雙向傳輸。
超文本:什麼是超文本?
超文本包含的內容非常廣泛,文本、圖片、音頻、視頻和動畫等等這些多媒體信息,都屬於超文本。
協議:它是哪個層次的協議,基於的下層協議是誰?
HTTP 是應用層的協議,使用 TCP 作為傳輸層支撐協議,默認埠號是80。
簡單回答了這三個問題,現在我們可以解釋 HTTP 是什麼了?
HTTP 是一個應用層的協議,它定義了瀏覽器(客戶端)訪問網站(伺服器)的數據格式和規則,即瀏覽器客戶端如何請求資源,網站伺服器如何響應請求,並將資源發送給瀏覽器。當然,這裡的資源指的就是超文本。
這麼一說,大家是不是就不覺得陌生了呢?因為我們每天通過瀏覽器上網,都是使用的 HTTP 協議。我們在瀏覽器中輸入網站的地址,瀏覽器向網站發起資源請求,網站將網頁內容的超文本信息發送給瀏覽器,瀏覽器解析內容之後進行渲染,最終展現給我們的就是這個網站的內容。
HTTP訪問網站HTTP的關鍵要素 URL前面說到,瀏覽器發起的是對web伺服器上資源的訪問,網際網路上有很多這樣的伺服器,對應的資源是海量的,那我們如何標識這些資源呢?簡單來說,就是伺服器如何確定瀏覽器是要訪問自己,並且需要請求的具體是哪個資源。
為了在網絡當中標識資源的唯一性,我們給資源了定義了一個格式統一而且唯一的網絡地址,這個網絡地址稱為 URL(Uniform Resource Locator),即統一資源定位符。URL 由三部分組成:協議類型、存放資源的主機域名或者 IP 地址、主機提供服務的埠、資源目錄、資源文件名,格式為:協議類型://<主機域名或IP位址>:<埠>/<資源目錄>/<資源文件名>。
URL格式示例協議類型表示我們通過什麼協議訪問資源,常用的協議類型有 ftp 、http 和 thunder 等等,我們現在講的就是通過 HTTP 來訪問web伺服器的資源。
主機域名或 IP 地址是Web伺服器在網絡上的標識,每個Web伺服器都有自己特有的域名或者唯一的IP位址。用戶要訪問某個資源,一定要先確定資源所在伺服器的域名或者 IP 地址。比如小智想要訪問世界上第一個網站,就在瀏覽器中輸入它的域名 http://info.cern.ch。
對於埠,一般標準的應用層協議都給它分配了一個固定埠,如果伺服器使用了這個固定埠,在瀏覽器輸入 URL 時就可以不用包含。比如,HTTP 默認使用固定埠號 80,cern 網站使用的就是 80 埠,所以我們訪問它的 URL 就可以省略埠。
資源目錄指的是資源在Web伺服器上的存儲路徑,伺服器上資源的管理跟我們使用的電腦管理文件的方式非常類似,採用的都是樹狀的文件夾的方式,伺服器有很多很多的目錄,每個目錄又可以包含各種目錄以及資源文件,如果不指定路徑或者指定的為"/",用戶訪問的就是伺服器的首頁,也就是伺服器資源目錄的根目錄。
比如小智訪問http://info.cern.ch/hypertext/WWW/TheProject.html,就是訪問域名為 http://info.cern.ch 的Web伺服器上 hypertext 目錄下 WWW 目錄中的的 TheProject.html 文件。
資源文件目錄結構方法對伺服器的資源進行地址唯一標識只是完成了第一步,現在瀏覽器可能會對資源進行不同的操作:
所以,Web伺服器還得知道瀏覽器具體想對資源進行什麼類型的操作,以便做出對應的回應。為了規定瀏覽器對資源的操作類型,HTTP 定義了相應的操作方法,小智這裡整理出了一張表,包含了每種方法對應的含義以及它的使用場景:
HTTP方法狀態碼瀏覽器發起資源請求後,Web伺服器並不是每次都會響應成功,出現的問題可能各種各樣:
比如要訪問的資源已經被刪除,不存在了;
比如用戶沒有權限訪問;
比如伺服器開了小差,無法響應;
這些情況下,伺服器該如何通知瀏覽器呢?這個時候,就該 HTTP 的狀態碼上場了。狀態碼,簡單理解就是瀏覽器客戶端和伺服器之間,定義的一個通用的有含義的代號。伺服器每次回應時,把這個代號帶上,瀏覽器就能很清楚的知道伺服器的響應狀態了。當然,為了讓大家很清晰的知道每個狀態的含義,每個狀態都有一個對應的簡短描述,我們叫它原因短語。
HTTP 狀態碼由三位十進位數字組成,第一位表示狀態碼的類型。HTTP 狀態碼分為五大類:
HTTP狀態碼分類常用狀態碼如下:
1xx 提示性狀態碼「100 Continue」已收到請求的初始部分,請客戶端繼續。
「101 Switching Protocols」伺服器正在根據客戶端的請求切換協議,只能切換到HTTP 更高版本的協議。
2xx 成功狀態碼「200 OK」表示請求成功,客戶端的請求已被正常處理。
「201 Created」表示請求已被正常處理,伺服器創建了新的資源,比如用在對PUT方法創建文件的響應。
「202 Accepted」表示已經接受請求,但未處理完成。
「204 No Content」表示請求已被正常處理,與200 OK 不同的是,響應消息不包含數據內容。
「206 Partial Content」表示客戶端發起的是範圍請求,只請求資源的一部分,伺服器已經正常響應這次請求的數據,常應用於 HTTP 分塊下載或斷點續傳,
3xx 重定向狀態碼「301 Moved Permanently」表示永久重定向,請求資源的URL已更新,以後需改用新的 URL 訪問,響應頭裡 Location 欄位攜帶有URL,瀏覽器會自動跳轉。
「302 Found」表示臨時重定向,請求的資源還在,暫時需要用另一個 URL 來訪問,將來的請求仍然使用老的URL,響應頭裡 Location 欄位攜帶有URL,瀏覽器會自動跳轉。
「303 See Other」表示請求的資源存在另外一個URL,客戶端用這個URL去請求。
「304 Not Modified」所請求的資源未修改,伺服器返回此狀態碼時,不會返回任何資源,常用於緩存控制。
4xx 客戶端錯誤狀態碼「400 Bad Request」表示客戶端發送了一個錯誤的請求。
「401 Unauthorized」表示需要客戶端進行身份認證。
「403 Forbidden」表示訪問請求被伺服器拒絕,並且通常伺服器不想告訴客戶端被拒絕的原因。
「404 Not Found」表示在伺服器上無法找到請求的資源,無法提供給客戶端。
「405 Method Not Allowed」表示伺服器不支持客戶端對資源的請求方法。
「408 Request Timeout」表示由於等待客戶端發送請求的時間過長,伺服器關閉連接。
5xx 伺服器錯誤狀態碼「500 Internal Server Error」表示伺服器內部發生了錯誤,無法處理請求,但具體發生了什麼錯誤,我們並不知道。
「501 Not Implemented」表示伺服器不支持客戶端請求的功能。
「502 Bad Gateway」表示伺服器自身工作正常,訪問後端伺服器發生了錯誤,通常是伺服器作為網關或代理時返回的錯誤碼。
「503 Service Unavailable」表示伺服器當前很忙,暫時無法響應客戶端的請求。
「505 HTTP Version Not Supported」表示伺服器不支持請求的HTTP協議版本,無法處理請求。
HTTP報文HTTP協議的交互過程,就是一個資源請求和應答的過程。從數據報文來看,HTTP報文可以分為兩類:請求報文和響應報文。瀏覽器客戶端發出的報文為請求報文,伺服器發出的報文為響應報文。
請求報文請求報文分為請求行、首部欄位和主體(HTTP 要傳輸的內容)三部分。其中首部欄位又分為請求首部欄位、通用首部欄位和主體首部欄位。另外,主體部分可以沒有,比如 GET 請求報文就沒有主體部分。
HTTP請求報文響應報文響應報文分為狀態行、首部欄位和主體(HTTP 要傳輸的內容)三部分。其中首部欄位又分為響應首部欄位、通用首部欄位和主體首部欄位。
報文交互過程為了更實際的了解 HTTP 的報文結構以及交互流程,我們通過 curl 工具抓取訪問http://info.cern.ch/hypertext/WWW/TheProject.html 頁面的 HTTP 報文來分析一下。具體抓包步驟在上一章節咱們已經講過,這裡不再贅述。
打開抓取到的 HTTP 報文,進行 IP 地址過濾後,可以看到訪問網頁的 HTTP 報文交互流程:
HTTP報文首先是 TCP 建立連接的三次握手,接著 curl 客戶端發起 HTTP GET 請求,然後伺服器回應HTTP 200 OK,最後 TCP 四次揮手結束連接(這裡抓到的包,其實伺服器還沒有發起 FIN 包來結束連接),正常訪問流程就結束了。
HTTP報文交互流程在 HTTP 的早期版本,使用的是短連接的方式,就是伺服器每次連接只處理一個請求,處理完即斷開連接。這種方式在資源請求頻繁的場景下,比如瀏覽器打開一個有很多資源類型的網頁,會發起很多次請求,每次請求就都需要重新發起 TCP 連接,從而影響傳輸性能,也增加了伺服器的處理開銷。在 HTTP 1.1 版本中,默認都採用了持久連接的方式,通信任何一方沒有提出斷口連接,即保持連接狀態,以便下次進行資源請求。
HTTP持久連接現在我們想清晰的看到HTTP請求和響應的具體內容,就要用到Wireshark追蹤流的功能,流追蹤功能首先選中這條流的某個報文,然後右鍵,點擊追蹤流選項的HTTP流,像下圖這樣:
Wireshark追蹤流功能這裡說明一下報文流的概念,流也稱為一個會話或者一次連接,就是源IP、源埠、目的IP、目的埠和傳輸層協議號這五元組完全一樣(報文交互是雙向的,源和目的可以互換)的一組報文,瀏覽器打開一個網頁,會有一條或者多條流。
對我們抓取的HTTP報文進行流追蹤後,可以看到:
HTTP流追蹤分析怎麼樣,通過Wireshark對報文的分析,HTTP 報文的結構是不是看起來就一目了然了呢?
首部欄位方法、URL和狀態碼我們都已經講過了,現在輪到 HTTP 中非常重要的首部欄位了。綜合 HTTP 的請求報文和響應報文的首部欄位,首部欄位分為四種,即通用首部欄位、請求首部欄位、響應首部欄位和主體首部欄位。
通用首部欄位通用首部欄位指的是請求報文和響應報文都會使用到的首部欄位,它提供與報文相關的最基本的信息。常用的通用首部欄位如下:
請求首部欄位請求首部欄位指的是只在請求報文中使用到的首部欄位,用於補充請求的附加信息和客戶端信息。常用的請求首部欄位如下:
Accept: 客戶端能接受的數據類型,例如 Accept: text/html,表示客戶端支持 text/html 數據類型。
Accept-Charset: 客戶端能接受的字符集,例如:Accept-Charset:UTF-8,表示客戶端支持 UTF-8 編碼。
Accept-Encoding: 客戶端能接受的內容編碼,例如:Accept-Encoding: gzip,表示客戶端支持 gzip 壓縮。
Accept-Language: 客戶端能接受的語言類型,例如:Accept-Language:zh-cn,zh,表示客戶端支持中文。
Host: 用來指定要訪問的伺服器的域名,例如:Host: info.cern.ch,表示客戶端訪問域名為 info.cern.ch 的伺服器。
User-Agent: 客戶端發起請求的瀏覽器類型,例如:User-Agent: curl/7.61.1,表示發起瀏覽器請求的是curl,版本是7.61.1。
Referer: 客戶端發起的請求來源於哪個URL,例如:Referer:http://info.cern.ch/,表示發起的請求來源於 http://info.cern.ch/ 這個網頁。
Cookie: 用於伺服器對瀏覽器客戶端的識別和狀態管理,它與響應首部欄位 Set-Cookie 配合使用,客戶端進行請求認證後,伺服器在響應報文裡面使用 Set-Cookie 欄位為客戶端分配一個唯一的Cookie值,瀏覽器會保存這個Cookie,下次訪問伺服器時會在請求報文中攜帶Cookie欄位,伺服器就可以識別這個客戶端。
響應首部欄位響應首部欄位指的是只在響應報文中使用到的首部欄位,用於補充響應的附加信息和伺服器信息。常用的響應首部欄位如下:
Location: 配合 HTTP 3xx 重定向狀態碼使用,伺服器告訴客戶端通過這個新的 URL 訪問資源,例如:Location:http://info.cern.ch/hypertext/WWW/TheProject.html,表示客戶端需要去這個新的URL訪問資源。
Server: 伺服器的應用程式信息,例如:Server: Apache,表示伺服器使用的應用程式是Apache。
Set-Cookie: 與請求首部欄位 Cookie 對應,用於伺服器對客戶端的識別和狀態管理。
主體首部欄位主體首部欄位指的是請求報文和響應報文中主體部分使用的首部欄位,用於補充內容的更新時間和主體相關信息。常用的主體首部欄位如下:
Content-Type: 說明主體內容的數據類型和字符集,與請求首部欄位的 Accept 和 Accept-Charset 對應,例如 Content-Type: text/html; charset=UTF-8,表示主體內容數據類型為 text/html,字符集為 UTF-8。
Content-Encoding: 說明主體內容的內容編碼方式,與請求首部欄位的 Accept-Encoding 對應,例如 Content-Encoding: gzip,表示主體內容的編碼方式是 gzip。
Content-Language: 說明主體內容使用的語言類型,與請求首部欄位的 Accept-Language 對應,例如 Content-Language:zh-CN, 表示主體內容的語言類型是中文。
Content-Length: 說明主體內容的長度,單位為字節,比如 Content-Length: 1000,表示主體內容的長度是1000位元組。
Content-MD5: 伺服器對主體內容進行MD5加密之後的值,客戶端收到主體內容後,對主體內容進行 MD5 計算之後與 Content-MD5 的值進行比較,用於校驗主體內容的完整性。
Allow: 說明伺服器能支持的對資源請求的 HTTP 方法,與 HEAD 請求對應,例如 Allow: GET,HEAD,表示伺服器支持對資源進行 GET 和 HEAD 請求。
Last-Modified: 說明資源最後被修改的時間,例如:Last-Modified: Thu, 03 Dec 1992 08:37:20 GMT。
Etag: 表示主體內容的標識,伺服器會為每份資源分配唯一的 Etag 值,例如同一網頁的中文版和英文版的URL相同,但是 Etag 不同。
HTTP的優缺點HTTP 的關鍵內容,小智差不多就講完了,現在咱們一起總結一下 HTTP 有哪些優點和缺點:
優點1)使用簡單:瀏覽器請求資源時,只需要傳送操作方法和資源路徑,頭部內容採用靈活的key-value形式。
2)跨平臺:與平臺和開發語言無關,可以跨平臺運行。
3)應用廣泛:能夠傳輸文本、圖片、音頻、視頻和動畫等各種資源類型,可以被廣泛應用於各種場景。
4)易擴展:HTTP的方法、狀態碼和首部欄位都可以根據實際需要進行自定義擴展。
缺點1)無狀態:伺服器對於事務處理沒有記憶能力,不知道客戶端是什麼狀態。即我們給伺服器發送 HTTP 請求之後,伺服器根據請求,會給我們發送數據過來,但是伺服器發送完不會記錄任何信息。雖然這樣伺服器處理請求簡單,可以減少伺服器資源的佔用,但是在某些場景下,顯然不能滿足客戶端用戶的需求,比如用戶登錄了網站之後在各個頁面跳轉,顯然不可能訪問每個網頁都進行登錄一遍。
當然,針對無狀態的問題, HTTP 在 1.1 版本中使用 Cookie 技術進行了優化,使得伺服器能識別客戶端,並記住客戶端的狀態。
Cookie技2)不安全:HTTP 最大的缺點應該就是,它採用明文傳輸通信內容導致的不安全性,主要表現在:
明文傳輸內容,信息可能會竊聽,比如我們登陸網站的帳號密碼,可能被不法分子輕易截獲;
無法驗證通信雙方身份的真偽,可能會被偽裝欺騙,比如我們可能被欺騙,導致訪問假冒的購物網站;
無法驗證數據的完整性,傳輸內容會被篡改,比如我們打開網頁時,被惡意植入廣告;
針對 HTTP 明文傳輸的不安全性問題,越來越多的伺服器採用了加密的 HTTPS 協議來傳輸數據,關於 HTTPS 的實現機制,小智後面會單獨做深入的分析。
HTTP的版本演進在請求報文的請求行中,還有一個 HTTP 的版本欄位,我們也來簡單了解一下 HTTP 的版本演進歷史。HTTP 分為 0.9、1.0、1.1、2.0和3.0,共五個版本,其中 1.1 版本是現在主流使用的版本。
HTTP/0.9HTTP 的第一個版本,功能過於簡單,只支持 GET 請求方法,只能傳輸文本信息,無法滿足需求。
HTTP/1.0報文必須包含 HTTP 頭信息,請求行中需要指定 HTTP 的版本;
增加支持 POST 和 HEAD 方法;
根據首部欄位 Content-Type 欄位,可以支持多種數據類型的傳輸;
但是 HTTP 1.0 是短連接的方式,每次請求完成,需要重新發起 TCP 連接過程,性能很差。
HTTP/1.1引入持久連接機制並被默認採用,多個請求可以共用一個 TCP 連接;
增加支持PUT、PATCH、OPTIONS 和 DELETE 方法;
增加支持斷點續傳;
支持管道方式,同一連接下多個請求可以同時發送,提高傳輸速度,比如瀏覽器要發起 A 和 B 兩個請求,發送 B 請求時,不用等到 A 請求的回應到達時才發送,而是可以將 A 請求和 B 請求同時發送。需要說明的是,這裡只是說瀏覽器可以同時發送請求,但是伺服器還是按順序處理請求的,所以請求的響應速度還是取決於伺服器串行處理請求的能力。
HTTP/2.0增加雙工模式,一個 TCP 連接裡,不僅客戶端可以同時發送請求,伺服器也可以同時並行處理請求;
引入頭部壓縮機制,使用gzip等方式壓縮 HTTP 頭部信息,提高帶寬使用率;
頭信息和數據體不再是文本信息,而是使用二進位;
允許伺服器主動向客戶端發送資源,即伺服器推送(server push)。
HTTP/3.0基於 Google 的 QUIC協議,底層使用 UDP 進行數據傳輸,上層仍然使用 HTTP 2.0,所以相對於 HTTP 2.0,HTTP 3.0 最大的不同應該是 UDP 和 TCP 之間的不同,就是 UDP 採用的是無連接傳輸。
總結好了,小夥伴們,HTTP 相關的內容到這裡就要告一段落了,讓我們一起再來回顧一下這個章節所講的內容吧:
首先,我們了解了 HTTP 是什麼,知道它是在瀏覽器客戶端和伺服器之間傳輸超文本資源的一種應用層協議,它使用非常廣泛,我們每天通過瀏覽器上網都會使用到它;
接著,我們分析了 HTTP 通信需要的三個關鍵要素:URL用來唯一標識網絡上的各種資源,方法用來確定對資源的操作類型,狀態碼用來告知資源操作的結果,三個要素缺一不可;
然後,我們通過實際環境抓取 HTTP 報文,對 HTTP 報文的結構和交互流程進行了詳細分析,另外,報文中涉及到非常重要的首部欄位,所以我們把常用的首部欄位都梳理了一遍;
再接著,我們總結了一下HTTP的優點和缺點,HTTP 使用廣泛,優點很多,但是最大的缺點就是明文傳輸,導致信息容易被竊取和篡改;
最後,我們了解了一下 HTTP 的版本歷史,發現 HTTP 一直在改進迭代,希望讓自己變得更完美。
在下一章節,我們將學習應用層的 DNS 協議。