1. 程式人生 > >【計網】圖解HTTP常見知識點總結

【計網】圖解HTTP常見知識點總結

## 目錄 [TOC] ## 初識TCP/IP ​ 瞭解HTTP之前我們得了解一下TCP/IP協議族。我們通常所說得TCP/IP協議族是網際網路相關的各類協議族的總稱,而HTTP屬於它內部的一個子集。還有一種說法認為TCP/IP是指TCP和IP這兩種協議。 ​ TCP/IP協議族裡重要的一點就是分層。從上到下依次分為以下4層:應用層、傳輸層、網路層和資料鏈路層。 ### TCP/IP協議族4層模型 **應用層** ​ 應用層的任務是通過應用程序間的互動來完成特定的網路應用。TPC/IP協議族內預存了各類通用的應用服務。比如,FTP(文字傳輸協議)和DNS(域名系統)。HTTP協議也位於該層。 **傳輸層** ​ 傳輸層主要為兩臺計算機程序之前的通訊提供資料傳輸服務,也就是傳輸應用層的報文。該層的協議有:TCP協議和UDP協議。 **網路層** ​ 網路層用來處理網路上流動的資料包。資料包是網路傳輸的最小資料單。該層規定通過怎樣的路徑到達對方的計算機,並把資料包傳送給對方。在計算機網路中進行通訊,之間可能會經過很多網路裝置或者計算機,網路層就是要選擇合適的傳輸路線。網路層會把上一層的報文封裝成資料包。該層使用的是IP協議。 **鏈路層** ​ 用來處理連線網路的硬體部分。包括作業系統、硬體裝置的驅動、網絡卡和光纖等物理裝置。硬體上的範疇均在鏈路層的作用範圍之內。 ​ 傳送端在層與層之間傳輸資料時,沒經過一層必須要加上該層的首部資訊。反之,接收端在層與層傳輸時必須把首部去掉。這種把資料資訊包裝起來的做法叫做封裝。 ​ ![四層模型](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718163355164-2064263992.png) **** ​ 下面會講一講和HTTP密不可分的三個協議:IP、TCP、DNS **負責傳輸的IP協議** ​ IP協議的作用就是把各類資料包傳送給對方。為了確保傳送的準確,則需要滿足各類條件。其中兩個重要的條件就是IP地址和MAC地址。IP地址指明瞭節點被分配到的地址,MAC地址是指網絡卡所屬的固定地址。IP地址是可變換的,而MAC地址基本上不會改變。 ​ 網路通訊的雙方在同一區域網的情況很少,通常需要多臺網路裝置的中轉才能連線到對方。在中轉時,會利用下一站中轉裝置的MAC地址來搜尋下一個中轉目標。這時,會採用ARP協議,ARP是一種解析地址的協議,根據通訊方的IP地址就可以反查出對應的MAC地址。在這個中轉的過程中,那些計算機、路由器等網路裝置只能獲悉很粗略的傳輸路線,這種機制稱為路由選擇。 ​ ![路由選擇](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718163403917-988565748.png) **確保可靠性的TCP協議** ​ TCP位於傳輸層,提供可靠的位元組流服務。所謂位元組流服務,就是為了方便傳輸,TCP會將大資料分割成以報文段為單位的資料包進行管理。而可靠性涉及到的東西就很多了,比如三次握手、超時重傳、流量控制等等。這一塊會放到TCP/UDP的總結部落格裡面講,暫時只需要知道TCP建立連線會經過三次握手,斷開連線會經過四次揮手。 **負責域名解析的DNS服務** ​ DNS和HTTP一樣位於應用層。它提供域名到IP地址之間的解析服務。所謂域名就是類似於www.baidu.com這種字串。為了方便記憶,計算機也可以被賦予域名。這樣我們就可以直接通過域名訪問,而不是毫無字面意義的IP地址。但是要讓計算機去理解域名,就有些困難了。為了解決這個問題,就需要用到DNS服務了。DNS提供域名查IP和IP查域名的服務。 ![DNS服務](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718163409740-1801936320.png) **在瀏覽器上輸入一個域名會發生什麼?** ​ 最後,我們以一個常見的面試題,來總結一下在使用HTTP協議進行通訊的過程中,IP協議、TCP協議和DNS服務發揮了哪些作用。 ![瀏覽網頁過程](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718163414294-1470451524.png) **URI和URL** ​ URL就是我們使用瀏覽器訪問WEB網頁時輸入的網頁地址,比如:https://www.baidu.com/。URL的全稱是統一資源定位符。 ​ 而URI是統一資源識別符號。URI用字串標識某一網際網路資源,而URL標識資源的地點,所以URL是URI的子集。為了讓你更直觀的認識URI,可以瞭解以下URI的格式: ![URI格式](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718163417375-887402009.png) ​ 登入資訊為指定使用者名稱和密碼,作為訪問伺服器資源的登入資訊,此項是可選項。伺服器地址就是域名,也可以是IP。埠號也是可選項,不填的就會使用預設埠號。檔案路徑就是伺服器上該資源的路徑。查詢字串就是傳入到伺服器的引數。片段識別符號也是可選項,它通常可以標記出已獲取資源中的某個位置。 ## 初識HTTP ### 請求和響應 ​ HTTP協議的作用是用於客戶端和伺服器端之間的通訊。通過請求和響應的互動達成通訊。HTTP協議規定,請求從客戶端發出,最後服務端響應請求並返回。 ​ 下面來看看請求報文的構成 ![請求報文的構成](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718164416672-669468396.png) ​ 方法就是請求的型別,URI上一節講過。協議版本就是HTTP的版本號,其他的部分待會再說。下面再看看響應報文的構成 ​ ![響應報文的構成](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718164932595-620568613.png) ​ 狀態碼能反應該次請求的結果如何,圖中的200就代表請求成功。 ​ HTTP是一種無狀態的協議,即HTTP協議本身不對請求和響應之間的通訊狀態進行儲存。雖然其本身不能儲存,但是為了實現保持狀態的功能,於是引入了Cookie技術。關於Cookie後面再說。 ​ 接下來詳細說說前面提到的請求型別,也就是方法的意義。下面介紹以下HTTP/1.1中可使用的部分方法。 **GET:獲取資源** ​ GET方法用來請求訪問被URI識別的資源,如果請求的是文字圖片這些資源,那就保持原樣返回。如果請求的是介面,那麼就返回程式執行的返回結果。 **POST:傳輸資料** ​ 雖然我們也可以利用GET方法的引數來傳輸資源,但是一般還是用POST方法。雖然它們功能很相似,但是最主要的一個區別就是:GET方法的引數會顯示在URI上,也就是以?號開頭的。而POST方法的引數會放在主體裡面。這樣對於傳輸資料來說,顯然會安全一點。 **PUT:傳輸檔案** ​ 要求在請求報文的主體中包含檔案內容,然後儲存到URI指定的位置。 **HEAD:獲得報文首部** ​ HEAD方法和GET方法一樣,只是不返回報文主體部分。用於確認URI的有效性以及資源更新的日期時間等。 **DELETE:刪除檔案** ​ 與PUT方法相反,DELETE請求刪除URI指定的資源。但是和PUT一樣,它們都不帶驗證機制,所以一般的話也不會使用PUT或者DELETE,都可以用POST替代,然後配合程式程式碼來驗證刪除。 **OPTIONS:查詢支援的方法** ​ 用以查詢URI指定資源支援的方法。 接著再說說前面提到的Cookie **Cookie** ​ Cookie可以解決HTTP無狀態的問題。Cookie會根據從服務端返回的響應報文中的一個叫Set-Cookie的首部欄位資訊,來通知客戶端儲存Cookie。當下次客戶端再次請求該服務端時就會在請求報文中加入Cookie值。常見的場景就是登入。首先客戶端傳送登入請求,登入成功後服務端返回使用者資訊,然後客戶端把使用者資訊存入Cookie,這樣使用者的登入狀態就保持住了。當然,一般不會直接把使用者資訊存入Cookie,畢竟Cookie是存在客戶端的,很不安全,一般會配合Session來使用。比如把使用者資訊存到服務端的Session中,給客戶端返回SessionID,這樣一樣可以查詢出使用者資訊。 ​ 下面展示Cookie在請求響應中的樣子 ![Cookie](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200718172552174-772400411.png) ## HTTP報文 ​ 請求和響應之間交換的資訊就被稱為HTTP報文。請求方的叫做請求報文,響應方的叫做響應報文。HTTP報文大致可分為首部和主體兩部分。詳細的可見下圖 ![HTTP報文](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719084621317-1752195734.png) ​ 其中,請求行包含請求的方法,請求的URI和HTTP的版本。狀態行包含響應結果的狀態碼和HTTP版本,狀態碼就比如前面提到的200,它代表請求成功,更多的狀態碼和各種首部欄位待會再詳說。其他則包含Cookie等資訊。 ### HTTP狀態碼 ​ 狀態碼的職責是客戶端傳送請求後,描述返回的請求結果。藉助狀態碼我們就可以知道該次請求在服務端是否正常處理了。狀態碼以開頭的數字主要分為5大類: ![HTTP狀態碼](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719091026318-1766123249.png) ​ 我們只要遵循狀態碼類別的定義,即使在服務端建立自己的狀態碼都沒問題。如果要列舉每一個狀態碼,數量非常繁多,下面就介紹一下具有代表性的十幾個狀態碼。 **2XX:代表成功** ​ 200 OK:表示客戶端傳送的請求在服務端被正常處理。 ​ 204 No Content:表示請求已被成功處理,但在返回的響應報文中沒用返回資源。 ​ 206 Partial Content:表示客戶端進行了範圍請求,而伺服器成功執行了這部分的GET請求。響應報文中包含由Content-Range指定範圍的實體內容。這裡說一下,此處的範圍請求不是我們業務程式碼上的範圍查詢,而是HTTP的範圍請求。在以前網速不是很快的情況下下載一個資源,可能會發生網路中斷,如果網路恢復的話就需要從頭下載。這時候就會想要從上次斷開的地方接著下載,那麼就必須有一種請求可以支援範圍請求。比如對一份10000位元組大小的資源進行範圍請求,可以只請求5001~10000位元組內的資源。請求、響應報文的內容如下圖: ![範圍請求](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719092344588-594689832.png) **3XX:代表重定向** ​ 301 Moved Permanently:永久性重定向,表示請求的資源已被分配到新的URI,以後應該使用資源現在所指的URI。 ​ 302 Found:臨時性重定向,表示請求的資源已被分配到新的URI,本次請求應該使用新的URI。 ​ 303 See Other:該狀態碼功能上和302相同,但是303明確表示客戶端應該採用GET方法獲取資源。 ​ 304 Not Modified:表示資源已找到,但是不符合請求的條件。 **4XX:代表客戶端錯誤** ​ 400 Bad Request:表示請求報文中存在語法錯誤,需要修改請求內容後再次傳送請求。 ​ 401 Unauthorized:表示傳送的請求需要通過HTTP認證。當瀏覽器初次接收到401響應時,會彈出認證用的對話視窗。 ​ 403 Forbidden:表示請求的資源被伺服器拒絕了。拒絕的理由可以在主體部分進行說明。一般是沒用訪問許可權才會出現這個問題。 ​ 404 Not Found:表示伺服器上無法找到請求的資源。 **5XX:代表服務端錯誤** ​ 500 Internal Server Error:表示服務端執行請求時發生錯誤,一般是服務端程式碼出現了問題。 ​ 503 Service Unavailable:表示伺服器暫時處於超負載或者正在進行停機維護。 ### HTTP報文首部 ​ 前面說到過,HTTP報文主要分為報文首部和主體。首部內容為客戶端和服務端分別處理請求和響應提供所需的資訊。具體的資訊可以往上翻一點,看看那個截圖。 ​ HTTP首部欄位是由首部欄位名稱和欄位值構成,中間用冒號分隔。例如: > Content-Type:text/html > > Keep-Alive:timeout,max=100 (多個欄位值用夠好分開) ​ 首部欄位主要分為4種類型: **通用首部欄位,請求報文和響應報文兩方都會使用的首部** ![通用首部欄位](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719101457004-2114107092.png) **請求首部欄位,請求報文使用的首部欄位,補充了請求的附加內容、客戶端資訊等資訊** ![請求首部欄位](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719101537171-725724463.png) **響應首部欄位,響應報文使用的首部欄位** ![響應首部欄位](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719101703684-1397954794.png) **實體首部欄位,針對請求和響應報文的實體部分使用的首部欄位** ![實體首部欄位](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719101724663-817997240.png) 以上只是HTTP/1.1規範定義的47種首部欄位,並不代表全部。比如常用的Cookie、Set-Cookie均未出現在其中。下面詳細說說幾個不好理解的欄位。 **Cache-Contro** ​ 該欄位可以根據後面的欄位值控制快取行為,如上面的報文結構圖中的no-cache代表不要快取的資源,需要源伺服器的資源。該欄位還有很多其他的值可供選擇,詳細的大家可以另行查詢。 **Connection** ​ 該欄位主要有兩個作用:控制不再轉發給代理的首部欄位和管理長連線。 ![Connection](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719104150885-188660624.png) ​ ​ HTTP/1.1版本預設的連線就是長連線,之前的版本預設都是短連結。長連線的好處就是提高請求的效率。如果是短連結的話,我們每次請求資源都要進行一次TCP連線(HTTP基於TCP),也就是三次握手。請求完後斷開連線,等下次請求資源再次握手。而長連線就是建立TCP連線後短時間內不斷開,期間可以進行多次HTTP請求。 **Via** ​ 該欄位是為了追蹤客戶端與服務端之間的請求和響應報文的傳輸路徑。報文經過代理伺服器或閘道器時,會現在Via欄位中附加該伺服器的資訊,然後再進行轉發。 ![Via](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719105503591-1866148117.png) **If-Match** ​ 帶有形如If-xxx這種形式的首部欄位的請求都可稱為條件請求。伺服器收到帶有附加條件的請求首先會判斷條件為真時才會執行請求。 ![If-Match](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719105939991-1591958064.png) ​ 只有當If-Match的值和Etag值一致時,伺服器才會接收請求。 **ETag** ​ 該欄位能告訴客戶端資源的唯一標識,當資源更新時這個標識也會改變。 #### 其他的首部欄位 **Set-Cookie和Cookie** ​ 下圖列舉了Set-Cookie的欄位值 ![Set-Cookie](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719111536028-1816621456.png) ​ Cookie的使用是非常常見的,大家可以隨便開啟一個網站,按F12開啟除錯,找到一個介面的請求,在響應首部裡面應該能看到Set-Cookie欄位,在請求首部應該能看到Cookie欄位。Set-Cookie欄位值的第一部分一般是一個字串=另一個字串,這就是上面的NAME=VALUE,name和value都是自定義的,然後請求時,Cookie就會帶上NAME=VALUE。 **DNT** ​ 該欄位屬於請求首部欄位,DNT是Do Not Track的簡稱,意為拒絕個人資訊被收集,是表示拒絕被精準廣告追蹤的一種方法。它的值只有0和1,0代表同意,1代表拒絕。 ## 確保WEB安全的HTTPS ​ 到此為止,我們瞭解到了HTTP優秀和方便的一面,它也有一些不足之處。如下: * 通訊沒有加密,內容可能被竊聽。 * 不驗證通訊方的身份,因此有可能遭遇偽裝 * 無法證明報文的完整性,所以有可能被篡改 **內容被竊聽** ​ 由於HTTP本身不具備加密(HTTP報文使用的是明文)的功能,所以也無法作到對通訊整體的加密。 由於網際網路的特點,無論世界上哪個角落的伺服器和客戶端進行通訊,在此通訊線路上的某些網路裝置都不可能是私有的,所以不排除在某個環節會遭到惡意的監聽。 ​ ![竊聽](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719140618176-555645406.png) ​ 而這個竊聽也並不是什麼難事,比如被廣泛使用的抓包工具Wireshark就可以實現。它可以獲取HTTP協議的請求和響應的內容,並對其進行解析。這個軟體我想應該有很多人知道,不過想要用好,還是得先學好TCP協議。 ​ 雖然HTTP協議中沒有加密機制,但是可以通過和SSL或TLS的組合使用,加密HTTP的通訊內容。用SSL建立安全通訊線路之後,就可以在這條線路上進行HTTP通訊了。**與SSL組合使用的HTTP就被稱為HTTPS**。 **身份遭遇偽裝** ​ HTTP協議的請求和響應不會對通訊方進行確認,也就是說返回響應的並不一定是我們請求的伺服器。而且任何人都可以向伺服器發起請求。雖然使用HTTP協議無法確定通訊方,但如果使用SSL則可以。SSL不僅提供加密,而且還使用了證書這種方法,來確認身份。證書一般由值得信任的第三方機構頒發,用以證明伺服器和客戶端是實際存在的。這些所謂的值得信任的第三機構一般是社會認可的企業或者組織機構。而且偽造證書這是一件非常困難的事情。 **內容被篡改** ​ 由於HTTP協議無法證明通訊報文的完整性,所以在請求或響應到達對方之前,報文的內容可能會被篡改。HTTPS又是如何發現內容被篡改的,下面就會仔細說說HTTPS的工作原理。 ### HTTPS工作原理 ​ 前面已經說過,HTTPS其實是一個披著SSL外殼的HTTP。而另外提到的TLS可以看作是SSL的最新版本或者升級版。 ![HTTPS](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719142348552-1907656091.png) ​ 在對SSL進行講解之前,我們先了解一下加密方法。SSL採用的是非對稱加密的方式。也就是說,加密是使用的是公鑰,而解密是使用的是私鑰。與之對應的是對稱加密,也就是加密和解密都是同一個金鑰,這種加密方式,我想不用說,都應該知道,運用在HTTP中依舊不安全,因為你需要把這個金鑰傳送給客戶端,這個期間有可能被其他人竊聽到金鑰。 ​ 而非對稱加密,公鑰是任何人都可以知道的,而私鑰則只有伺服器自己知道,這樣客戶端通過公鑰加密資訊,服務端通過私鑰解密。看似很安全了,但是別忘了HTTP的一個缺點,就是內容可能會被篡改。客戶端訪問HTTPS伺服器時,伺服器會先把公鑰傳送給客戶端,在這個過程中,如果有其他人篡改公鑰,把公鑰換成自己的,那麼就失去了加密的意義。反而是服務端無法解密資訊了。對於公鑰被篡改這個問題,我們待會再說,先說說HTTPS到底是怎麼實現加密的。 **HTTPS加密方式** ​ HTTPS採用的是對稱和非對稱混合式的加密機制。簡單地說就是客戶端得到公鑰後,會生成一個簡單的共享金鑰,然後把共享密碼用公鑰加密傳送給服務端,服務端解密後得到這個共享金鑰,之後的通訊就基於這個共享金鑰進行加密通訊。此時只有客戶端和服務端知道這個共享密碼,因為中途傳輸的是加密後的共享金鑰,即使被竊取了,沒有私鑰也解不開。 ![混合加密機制](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719143952479-2056024844.png) ​ 再接著說前面提到的,HTTPS是如何知道服務端給客戶端傳送公鑰時,公鑰有沒有被篡改。前面提到了證書,是由一些機構頒發的,一般稱為CA機構。這些機構一般會有自己的私有金鑰,它會對我們伺服器的公開金鑰做數字簽名,然後將這個已簽名的公開金鑰放入公鑰證書繫結在一起。到時候服務端往客戶端傳送公開金鑰時,會把金鑰和數字簽名一起傳送給客戶端。然後客戶端會根據CA機構的公鑰對這個數字簽名進行驗證,以確保公鑰沒有被篡改。但是你會發現,CA機構的公鑰是什麼鬼,期間並沒有傳送這個東西。一般這些CA機構的公鑰會內建在作業系統或者瀏覽器裡,所以不需要傳輸,這樣也確保了安全性。 ![數字簽名](https://img2020.cnblogs.com/blog/1383122/202007/1383122-20200719150116799-499129367.png) > 資料:《圖解